@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
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { CustomType } from "@prismicio/types-internal/lib/customtypes";
|
|
2
|
+
|
|
3
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
import * as v from "valibot";
|
|
6
|
+
|
|
7
|
+
import { buildTypes } from "./codegen-types";
|
|
8
|
+
import { findUpward } from "./lib/file";
|
|
9
|
+
import { stringify } from "./lib/json";
|
|
10
|
+
|
|
11
|
+
const HELP = `
|
|
12
|
+
Change a custom type's display name (label).
|
|
13
|
+
|
|
14
|
+
USAGE
|
|
15
|
+
prismic custom-type set-name <type-id> <new-name> [flags]
|
|
16
|
+
|
|
17
|
+
ARGUMENTS
|
|
18
|
+
type-id Custom type identifier (required)
|
|
19
|
+
new-name New display name (required)
|
|
20
|
+
|
|
21
|
+
Types are generated by default after changes. Use --no-types to skip.
|
|
22
|
+
|
|
23
|
+
FLAGS
|
|
24
|
+
--types string Output file for generated types (default: "prismicio-types.d.ts")
|
|
25
|
+
--no-types Skip type generation
|
|
26
|
+
-h, --help Show help for command
|
|
27
|
+
|
|
28
|
+
EXAMPLES
|
|
29
|
+
prismic custom-type set-name settings "Site Settings"
|
|
30
|
+
prismic custom-type set-name menu "Navigation Menu"
|
|
31
|
+
`.trim();
|
|
32
|
+
|
|
33
|
+
const CustomTypeSchema = v.object({
|
|
34
|
+
id: v.string(),
|
|
35
|
+
label: v.string(),
|
|
36
|
+
repeatable: v.boolean(),
|
|
37
|
+
status: v.boolean(),
|
|
38
|
+
format: v.optional(v.string()),
|
|
39
|
+
json: v.record(v.string(), v.record(v.string(), v.unknown())),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export async function customTypeSetName(): Promise<void> {
|
|
43
|
+
const {
|
|
44
|
+
values: { help, types, "no-types": noTypes },
|
|
45
|
+
positionals: [typeId, newName],
|
|
46
|
+
} = parseArgs({
|
|
47
|
+
args: process.argv.slice(4), // skip: node, script, "custom-type", "set-name"
|
|
48
|
+
options: {
|
|
49
|
+
types: { type: "string" },
|
|
50
|
+
"no-types": { type: "boolean" },
|
|
51
|
+
help: { type: "boolean", short: "h" },
|
|
52
|
+
},
|
|
53
|
+
allowPositionals: true,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (help) {
|
|
57
|
+
console.info(HELP);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!typeId) {
|
|
62
|
+
console.error("Missing required argument: type-id\n");
|
|
63
|
+
console.error("Usage: prismic custom-type set-name <type-id> <new-name>");
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!newName) {
|
|
69
|
+
console.error("Missing required argument: new-name\n");
|
|
70
|
+
console.error("Usage: prismic custom-type set-name <type-id> <new-name>");
|
|
71
|
+
process.exitCode = 1;
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const projectRoot = await findUpward("package.json");
|
|
76
|
+
if (!projectRoot) {
|
|
77
|
+
console.error("Could not find project root (no package.json found)");
|
|
78
|
+
process.exitCode = 1;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
|
|
83
|
+
|
|
84
|
+
// Read and parse the model
|
|
85
|
+
let model: CustomType;
|
|
86
|
+
try {
|
|
87
|
+
const contents = await readFile(modelPath, "utf8");
|
|
88
|
+
const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
|
|
89
|
+
if (!result.success) {
|
|
90
|
+
console.error(`Invalid custom type model: ${modelPath.href}`);
|
|
91
|
+
process.exitCode = 1;
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
model = result.output as CustomType;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
97
|
+
console.error(`Custom type not found: ${typeId}\n`);
|
|
98
|
+
console.error(`Create it first with: prismic custom-type create ${typeId}`);
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (error instanceof Error) {
|
|
103
|
+
console.error(`Failed to read custom type: ${error.message}`);
|
|
104
|
+
} else {
|
|
105
|
+
console.error("Failed to read custom type");
|
|
106
|
+
}
|
|
107
|
+
process.exitCode = 1;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Check if this is actually a custom type (not a page type)
|
|
112
|
+
if (model.format === "page") {
|
|
113
|
+
console.error(`"${typeId}" is not a custom type (format: page)`);
|
|
114
|
+
process.exitCode = 1;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Update the model
|
|
119
|
+
model.label = newName;
|
|
120
|
+
|
|
121
|
+
// Write updated model
|
|
122
|
+
try {
|
|
123
|
+
await writeFile(modelPath, stringify(model));
|
|
124
|
+
} catch (error) {
|
|
125
|
+
if (error instanceof Error) {
|
|
126
|
+
console.error(`Failed to update custom type: ${error.message}`);
|
|
127
|
+
} else {
|
|
128
|
+
console.error("Failed to update custom type");
|
|
129
|
+
}
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
console.info(`Renamed custom type "${typeId}" to "${newName}"`);
|
|
135
|
+
|
|
136
|
+
if (!noTypes) {
|
|
137
|
+
try {
|
|
138
|
+
await buildTypes({ output: types });
|
|
139
|
+
console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { CustomType } from "@prismicio/types-internal/lib/customtypes";
|
|
2
|
+
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
import * as v from "valibot";
|
|
6
|
+
|
|
7
|
+
import { findUpward } from "./lib/file";
|
|
8
|
+
|
|
9
|
+
const HELP = `
|
|
10
|
+
View details of a specific custom type.
|
|
11
|
+
|
|
12
|
+
USAGE
|
|
13
|
+
prismic custom-type view <type-id> [flags]
|
|
14
|
+
|
|
15
|
+
ARGUMENTS
|
|
16
|
+
type-id Custom type identifier (required)
|
|
17
|
+
|
|
18
|
+
FLAGS
|
|
19
|
+
--json Output as JSON
|
|
20
|
+
-h, --help Show help for command
|
|
21
|
+
|
|
22
|
+
EXAMPLES
|
|
23
|
+
prismic custom-type view settings
|
|
24
|
+
prismic custom-type view settings --json
|
|
25
|
+
`.trim();
|
|
26
|
+
|
|
27
|
+
const CustomTypeSchema = v.object({
|
|
28
|
+
id: v.string(),
|
|
29
|
+
label: v.string(),
|
|
30
|
+
repeatable: v.boolean(),
|
|
31
|
+
status: v.boolean(),
|
|
32
|
+
format: v.optional(v.string()),
|
|
33
|
+
json: v.record(v.string(), v.record(v.string(), v.unknown())),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export async function customTypeView(): Promise<void> {
|
|
37
|
+
const {
|
|
38
|
+
values: { help, json },
|
|
39
|
+
positionals: [typeId],
|
|
40
|
+
} = parseArgs({
|
|
41
|
+
args: process.argv.slice(4), // skip: node, script, "custom-type", "view"
|
|
42
|
+
options: {
|
|
43
|
+
json: { type: "boolean" },
|
|
44
|
+
help: { type: "boolean", short: "h" },
|
|
45
|
+
},
|
|
46
|
+
allowPositionals: true,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (help) {
|
|
50
|
+
console.info(HELP);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!typeId) {
|
|
55
|
+
console.error("Missing required argument: type-id\n");
|
|
56
|
+
console.error("Usage: prismic custom-type view <type-id>");
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const projectRoot = await findUpward("package.json");
|
|
62
|
+
if (!projectRoot) {
|
|
63
|
+
console.error("Could not find project root (no package.json found)");
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
|
|
69
|
+
|
|
70
|
+
let model: CustomType;
|
|
71
|
+
try {
|
|
72
|
+
const contents = await readFile(modelPath, "utf8");
|
|
73
|
+
const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
|
|
74
|
+
if (!result.success) {
|
|
75
|
+
console.error(`Invalid custom type model: ${modelPath.href}`);
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
model = result.output as CustomType;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
82
|
+
console.error(`Custom type not found: ${typeId}\n`);
|
|
83
|
+
console.error(`Create it first with: prismic custom-type create ${typeId}`);
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (error instanceof Error) {
|
|
88
|
+
console.error(`Failed to read custom type: ${error.message}`);
|
|
89
|
+
} else {
|
|
90
|
+
console.error("Failed to read custom type");
|
|
91
|
+
}
|
|
92
|
+
process.exitCode = 1;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Check if this is actually a custom type (not a page type)
|
|
97
|
+
if (model.format === "page") {
|
|
98
|
+
console.error(`"${typeId}" is not a custom type (format: page)`);
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (json) {
|
|
104
|
+
console.info(JSON.stringify(model, null, 2));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
console.info(`ID: ${model.id}`);
|
|
109
|
+
console.info(`Label: ${model.label}`);
|
|
110
|
+
console.info(`Repeatable: ${model.repeatable}`);
|
|
111
|
+
|
|
112
|
+
const tabs = Object.entries(model.json);
|
|
113
|
+
console.info(`\nTabs (${tabs.length}):`);
|
|
114
|
+
for (const [tabName, tabFields] of tabs) {
|
|
115
|
+
const fieldCount = Object.keys(tabFields).length;
|
|
116
|
+
console.info(` - ${tabName}: ${fieldCount} fields`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
|
|
3
|
+
import { customTypeAddField } from "./custom-type-add-field";
|
|
4
|
+
import { customTypeConnectSlice } from "./custom-type-connect-slice";
|
|
5
|
+
import { customTypeCreate } from "./custom-type-create";
|
|
6
|
+
import { customTypeDisconnectSlice } from "./custom-type-disconnect-slice";
|
|
7
|
+
import { customTypeList } from "./custom-type-list";
|
|
8
|
+
import { customTypeRemove } from "./custom-type-remove";
|
|
9
|
+
import { customTypeRemoveField } from "./custom-type-remove-field";
|
|
10
|
+
import { customTypeSetName } from "./custom-type-set-name";
|
|
11
|
+
import { customTypeView } from "./custom-type-view";
|
|
12
|
+
|
|
13
|
+
const HELP = `
|
|
14
|
+
Manage custom types in a Prismic repository.
|
|
15
|
+
|
|
16
|
+
USAGE
|
|
17
|
+
prismic custom-type <command> [flags]
|
|
18
|
+
|
|
19
|
+
COMMANDS
|
|
20
|
+
create Create a new custom type
|
|
21
|
+
list List all custom types
|
|
22
|
+
view View details of a custom type
|
|
23
|
+
remove Remove a custom type
|
|
24
|
+
set-name Change a custom type's display name
|
|
25
|
+
add-field Add a field to a custom type
|
|
26
|
+
remove-field Remove a field from a custom type
|
|
27
|
+
connect-slice Connect a shared slice to a custom type
|
|
28
|
+
disconnect-slice Disconnect a shared slice from a custom type
|
|
29
|
+
|
|
30
|
+
FLAGS
|
|
31
|
+
-h, --help Show help for command
|
|
32
|
+
|
|
33
|
+
LEARN MORE
|
|
34
|
+
Use \`prismic custom-type <command> --help\` for more information about a command.
|
|
35
|
+
`.trim();
|
|
36
|
+
|
|
37
|
+
export async function customType(): Promise<void> {
|
|
38
|
+
const {
|
|
39
|
+
positionals: [subcommand],
|
|
40
|
+
} = parseArgs({
|
|
41
|
+
args: process.argv.slice(3), // skip: node, script, "custom-type"
|
|
42
|
+
options: {
|
|
43
|
+
help: { type: "boolean", short: "h" },
|
|
44
|
+
},
|
|
45
|
+
allowPositionals: true,
|
|
46
|
+
strict: false,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
switch (subcommand) {
|
|
50
|
+
case "create":
|
|
51
|
+
await customTypeCreate();
|
|
52
|
+
break;
|
|
53
|
+
case "list":
|
|
54
|
+
await customTypeList();
|
|
55
|
+
break;
|
|
56
|
+
case "view":
|
|
57
|
+
await customTypeView();
|
|
58
|
+
break;
|
|
59
|
+
case "remove":
|
|
60
|
+
await customTypeRemove();
|
|
61
|
+
break;
|
|
62
|
+
case "set-name":
|
|
63
|
+
await customTypeSetName();
|
|
64
|
+
break;
|
|
65
|
+
case "add-field":
|
|
66
|
+
await customTypeAddField();
|
|
67
|
+
break;
|
|
68
|
+
case "remove-field":
|
|
69
|
+
await customTypeRemoveField();
|
|
70
|
+
break;
|
|
71
|
+
case "connect-slice":
|
|
72
|
+
await customTypeConnectSlice();
|
|
73
|
+
break;
|
|
74
|
+
case "disconnect-slice":
|
|
75
|
+
await customTypeDisconnectSlice();
|
|
76
|
+
break;
|
|
77
|
+
default: {
|
|
78
|
+
if (subcommand) {
|
|
79
|
+
console.error(`Unknown custom-type subcommand: ${subcommand}\n`);
|
|
80
|
+
process.exitCode = 1;
|
|
81
|
+
}
|
|
82
|
+
console.info(HELP);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
|
|
5
|
+
import packageJson from "../package.json" with { type: "json" };
|
|
6
|
+
import { codegen } from "./codegen";
|
|
7
|
+
import { customType } from "./custom-type";
|
|
8
|
+
import { init } from "./init";
|
|
9
|
+
import { locale } from "./locale";
|
|
10
|
+
import { login } from "./login";
|
|
11
|
+
import { logout } from "./logout";
|
|
12
|
+
import { pageType } from "./page-type";
|
|
13
|
+
import { preview } from "./preview";
|
|
14
|
+
import { pull } from "./pull";
|
|
15
|
+
import { push } from "./push";
|
|
16
|
+
import { repo } from "./repo";
|
|
17
|
+
import { slice } from "./slice";
|
|
18
|
+
import { status } from "./status";
|
|
19
|
+
import { token } from "./token";
|
|
20
|
+
import { webhook } from "./webhook";
|
|
21
|
+
import { whoami } from "./whoami";
|
|
22
|
+
|
|
23
|
+
const HELP = `
|
|
24
|
+
Prismic CLI for managing repositories and configurations.
|
|
25
|
+
|
|
26
|
+
USAGE
|
|
27
|
+
prismic <command> [flags]
|
|
28
|
+
|
|
29
|
+
COMMANDS
|
|
30
|
+
init Initialize a Prismic project
|
|
31
|
+
login Log in to Prismic
|
|
32
|
+
logout Log out of Prismic
|
|
33
|
+
whoami Show the currently logged in user
|
|
34
|
+
status Show the status of the current project
|
|
35
|
+
repo Manage Prismic repositories
|
|
36
|
+
locale Manage locales in a repository
|
|
37
|
+
page-type Manage page types in a repository
|
|
38
|
+
custom-type Manage custom types in a repository
|
|
39
|
+
slice Manage slices in a project
|
|
40
|
+
pull Pull types and slices from Prismic
|
|
41
|
+
push Push types and slices to Prismic
|
|
42
|
+
codegen Generate code from Prismic models
|
|
43
|
+
preview Manage preview configurations
|
|
44
|
+
token Manage API tokens in a repository
|
|
45
|
+
webhook Manage webhooks in a repository
|
|
46
|
+
|
|
47
|
+
FLAGS
|
|
48
|
+
-v, --version Show CLI version
|
|
49
|
+
-h, --help Show help for command
|
|
50
|
+
|
|
51
|
+
LEARN MORE
|
|
52
|
+
Use \`prismic <command> --help\` for more information about a command.
|
|
53
|
+
`.trim();
|
|
54
|
+
|
|
55
|
+
const {
|
|
56
|
+
positionals,
|
|
57
|
+
values: { version },
|
|
58
|
+
} = parseArgs({
|
|
59
|
+
options: {
|
|
60
|
+
help: { type: "boolean", short: "h" },
|
|
61
|
+
version: { type: "boolean", short: "v" },
|
|
62
|
+
},
|
|
63
|
+
allowPositionals: true,
|
|
64
|
+
strict: false,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (version) {
|
|
68
|
+
console.info(packageJson.version);
|
|
69
|
+
} else {
|
|
70
|
+
switch (positionals[0]) {
|
|
71
|
+
case "init":
|
|
72
|
+
await init();
|
|
73
|
+
break;
|
|
74
|
+
case "login":
|
|
75
|
+
await login();
|
|
76
|
+
break;
|
|
77
|
+
case "logout":
|
|
78
|
+
await logout();
|
|
79
|
+
break;
|
|
80
|
+
case "whoami":
|
|
81
|
+
await whoami();
|
|
82
|
+
break;
|
|
83
|
+
case "status":
|
|
84
|
+
await status();
|
|
85
|
+
break;
|
|
86
|
+
case "repo":
|
|
87
|
+
await repo();
|
|
88
|
+
break;
|
|
89
|
+
case "locale":
|
|
90
|
+
await locale();
|
|
91
|
+
break;
|
|
92
|
+
case "page-type":
|
|
93
|
+
await pageType();
|
|
94
|
+
break;
|
|
95
|
+
case "custom-type":
|
|
96
|
+
await customType();
|
|
97
|
+
break;
|
|
98
|
+
case "slice":
|
|
99
|
+
await slice();
|
|
100
|
+
break;
|
|
101
|
+
case "pull":
|
|
102
|
+
await pull();
|
|
103
|
+
break;
|
|
104
|
+
case "push":
|
|
105
|
+
await push();
|
|
106
|
+
break;
|
|
107
|
+
case "codegen":
|
|
108
|
+
await codegen();
|
|
109
|
+
break;
|
|
110
|
+
case "preview":
|
|
111
|
+
await preview();
|
|
112
|
+
break;
|
|
113
|
+
case "token":
|
|
114
|
+
await token();
|
|
115
|
+
break;
|
|
116
|
+
case "webhook":
|
|
117
|
+
await webhook();
|
|
118
|
+
break;
|
|
119
|
+
default: {
|
|
120
|
+
if (positionals[0]) {
|
|
121
|
+
console.error(`Unknown command: ${positionals[0]}`);
|
|
122
|
+
process.exitCode = 1;
|
|
123
|
+
}
|
|
124
|
+
console.info(HELP);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
package/src/init.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
|
|
3
|
+
import { createConfig, readConfig, UnknownProjectRoot } from "./lib/config";
|
|
4
|
+
|
|
5
|
+
const HELP = `
|
|
6
|
+
Initialize a Prismic project by creating a prismic.config.json file.
|
|
7
|
+
|
|
8
|
+
Use this command to connect an existing Prismic repository to your project.
|
|
9
|
+
To create a new repository, use \`prismic repo create\` instead.
|
|
10
|
+
|
|
11
|
+
USAGE
|
|
12
|
+
prismic init [flags]
|
|
13
|
+
|
|
14
|
+
FLAGS
|
|
15
|
+
-r, --repo Repository name (required)
|
|
16
|
+
-h, --help Show help for command
|
|
17
|
+
|
|
18
|
+
LEARN MORE
|
|
19
|
+
Use \`prismic <command> --help\` for more information about a command.
|
|
20
|
+
`.trim();
|
|
21
|
+
|
|
22
|
+
export async function init(): Promise<void> {
|
|
23
|
+
const { values } = parseArgs({
|
|
24
|
+
args: process.argv.slice(3),
|
|
25
|
+
options: {
|
|
26
|
+
help: { type: "boolean", short: "h" },
|
|
27
|
+
repo: { type: "string", short: "r" },
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (values.help) {
|
|
32
|
+
console.info(HELP);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!values.repo) {
|
|
37
|
+
console.error("Missing required flag: --repo");
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const existingConfig = await readConfig();
|
|
43
|
+
if (existingConfig.ok) {
|
|
44
|
+
console.error("A prismic.config.json file already exists.");
|
|
45
|
+
process.exitCode = 1;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const result = await createConfig({ repositoryName: values.repo });
|
|
50
|
+
|
|
51
|
+
if (!result.ok) {
|
|
52
|
+
if (result.error instanceof UnknownProjectRoot) {
|
|
53
|
+
console.error(
|
|
54
|
+
"Could not find a package.json file. Run this command from a project directory.",
|
|
55
|
+
);
|
|
56
|
+
} else {
|
|
57
|
+
console.error("Failed to create config file.");
|
|
58
|
+
}
|
|
59
|
+
process.exitCode = 1;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.info(`Created prismic.config.json for repository "${values.repo}"`);
|
|
64
|
+
}
|
package/src/lib/auth.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { access, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
|
|
5
|
+
import { appendTrailingSlash } from "./url";
|
|
6
|
+
|
|
7
|
+
const AUTH_FILE_PATH = new URL(".prismic", appendTrailingSlash(pathToFileURL(homedir())));
|
|
8
|
+
const DEFAULT_HOST = "https://prismic.io";
|
|
9
|
+
|
|
10
|
+
type AuthContents = {
|
|
11
|
+
token?: string;
|
|
12
|
+
host?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export async function saveToken(token: string, options?: { host?: string }): Promise<void> {
|
|
16
|
+
const contents: AuthContents = { token, host: options?.host };
|
|
17
|
+
await writeFile(AUTH_FILE_PATH, JSON.stringify(contents, null, 2));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function isAuthenticated(): Promise<boolean> {
|
|
21
|
+
const token = await readToken();
|
|
22
|
+
if (!token) return false;
|
|
23
|
+
|
|
24
|
+
// Verify token is still valid by calling the profile endpoint
|
|
25
|
+
try {
|
|
26
|
+
const host = await readHost();
|
|
27
|
+
host.hostname = `user-service.${host.hostname}`;
|
|
28
|
+
const url = new URL("profile", host);
|
|
29
|
+
|
|
30
|
+
const response = await fetch(url, {
|
|
31
|
+
headers: {
|
|
32
|
+
Accept: "application/json",
|
|
33
|
+
Cookie: `SESSION=fake_session; prismic-auth=${token}`,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
await removeToken();
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return true;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function readToken(): Promise<string | undefined> {
|
|
49
|
+
const auth = await readAuthFile();
|
|
50
|
+
return auth?.token;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function readHost(): Promise<URL> {
|
|
54
|
+
try {
|
|
55
|
+
const auth = await readAuthFile();
|
|
56
|
+
if (!auth?.host) return new URL(DEFAULT_HOST);
|
|
57
|
+
return new URL(auth.host);
|
|
58
|
+
} catch {
|
|
59
|
+
return new URL(DEFAULT_HOST);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function readAuthFile(): Promise<AuthContents | undefined> {
|
|
64
|
+
try {
|
|
65
|
+
const contents = await readFile(AUTH_FILE_PATH, "utf-8");
|
|
66
|
+
return JSON.parse(contents);
|
|
67
|
+
} catch {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function removeToken(): Promise<boolean> {
|
|
73
|
+
try {
|
|
74
|
+
await access(AUTH_FILE_PATH);
|
|
75
|
+
} catch {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const auth = await readAuthFile();
|
|
80
|
+
if (!auth) return false;
|
|
81
|
+
await rm(AUTH_FILE_PATH);
|
|
82
|
+
return true;
|
|
83
|
+
}
|