@angeloashmore/prismic-cli-poc 0.0.0-canary.1143872
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 +2508 -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 +222 -0
- package/src/custom-type-add-field-color.ts +205 -0
- package/src/custom-type-add-field-date.ts +208 -0
- package/src/custom-type-add-field-embed.ts +205 -0
- package/src/custom-type-add-field-geo-point.ts +202 -0
- package/src/custom-type-add-field-group.ts +179 -0
- package/src/custom-type-add-field-image.ts +205 -0
- package/src/custom-type-add-field-key-text.ts +205 -0
- package/src/custom-type-add-field-link.ts +228 -0
- package/src/custom-type-add-field-number.ts +237 -0
- package/src/custom-type-add-field-rich-text.ts +229 -0
- package/src/custom-type-add-field-select.ts +211 -0
- package/src/custom-type-add-field-timestamp.ts +208 -0
- package/src/custom-type-add-field-uid.ts +188 -0
- package/src/custom-type-add-field.ts +116 -0
- package/src/custom-type-connect-slice.ts +214 -0
- package/src/custom-type-create.ts +112 -0
- package/src/custom-type-disconnect-slice.ts +171 -0
- package/src/custom-type-list.ts +110 -0
- package/src/custom-type-remove-field.ts +171 -0
- package/src/custom-type-remove.ts +138 -0
- package/src/custom-type-set-name.ts +138 -0
- package/src/custom-type-view.ts +118 -0
- package/src/custom-type.ts +85 -0
- package/src/docs-fetch.ts +146 -0
- package/src/docs-list.ts +131 -0
- package/src/docs.ts +54 -0
- package/src/index.ts +132 -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/field-path.ts +81 -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 +238 -0
- package/src/page-type-add-field-color.ts +224 -0
- package/src/page-type-add-field-date.ts +227 -0
- package/src/page-type-add-field-embed.ts +224 -0
- package/src/page-type-add-field-geo-point.ts +221 -0
- package/src/page-type-add-field-group.ts +198 -0
- package/src/page-type-add-field-image.ts +224 -0
- package/src/page-type-add-field-key-text.ts +224 -0
- package/src/page-type-add-field-link.ts +247 -0
- package/src/page-type-add-field-number.ts +256 -0
- package/src/page-type-add-field-rich-text.ts +248 -0
- package/src/page-type-add-field-select.ts +230 -0
- package/src/page-type-add-field-timestamp.ts +227 -0
- package/src/page-type-add-field-uid.ts +207 -0
- package/src/page-type-add-field.ts +116 -0
- package/src/page-type-connect-slice.ts +214 -0
- package/src/page-type-create.ts +161 -0
- package/src/page-type-disconnect-slice.ts +171 -0
- package/src/page-type-list.ts +109 -0
- package/src/page-type-remove-field.ts +171 -0
- package/src/page-type-remove.ts +138 -0
- package/src/page-type-set-name.ts +138 -0
- package/src/page-type-set-repeatable.ts +147 -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 +242 -0
- package/src/push.ts +405 -0
- package/src/repo-create.ts +195 -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 +240 -0
- package/src/slice-add-field-color.ts +226 -0
- package/src/slice-add-field-date.ts +226 -0
- package/src/slice-add-field-embed.ts +226 -0
- package/src/slice-add-field-geo-point.ts +223 -0
- package/src/slice-add-field-group.ts +191 -0
- package/src/slice-add-field-image.ts +223 -0
- package/src/slice-add-field-key-text.ts +226 -0
- package/src/slice-add-field-link.ts +245 -0
- package/src/slice-add-field-number.ts +226 -0
- package/src/slice-add-field-rich-text.ts +250 -0
- package/src/slice-add-field-select.ts +232 -0
- package/src/slice-add-field-timestamp.ts +226 -0
- package/src/slice-add-field.ts +111 -0
- package/src/slice-add-variation.ts +139 -0
- package/src/slice-create.ts +203 -0
- package/src/slice-list-variations.ts +67 -0
- package/src/slice-list.ts +88 -0
- package/src/slice-remove-field.ts +122 -0
- package/src/slice-remove-variation.ts +112 -0
- package/src/slice-remove.ts +91 -0
- package/src/slice-rename.ts +122 -0
- package/src/slice-set-screenshot.ts +235 -0
- package/src/slice-view.ts +80 -0
- package/src/slice.ts +95 -0
- package/src/status.ts +873 -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,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
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
|
|
3
|
+
const HELP = `
|
|
4
|
+
Fetch and display documentation from Prismic's docs site.
|
|
5
|
+
|
|
6
|
+
USAGE
|
|
7
|
+
prismic docs fetch <path> [flags]
|
|
8
|
+
|
|
9
|
+
ARGUMENTS
|
|
10
|
+
path Documentation path with optional anchor (e.g., "nextjs" or "nextjs#set-up-a-prismic-client")
|
|
11
|
+
|
|
12
|
+
FLAGS
|
|
13
|
+
-h, --help Show help for command
|
|
14
|
+
|
|
15
|
+
EXAMPLES
|
|
16
|
+
prismic docs fetch nextjs
|
|
17
|
+
prismic docs fetch nextjs#set-up-a-prismic-client
|
|
18
|
+
|
|
19
|
+
LEARN MORE
|
|
20
|
+
Visit https://prismic.io/docs for the full documentation.
|
|
21
|
+
`.trim();
|
|
22
|
+
|
|
23
|
+
function parsePathAndAnchor(input: string): { path: string; anchor?: string } {
|
|
24
|
+
const hashIndex = input.indexOf("#");
|
|
25
|
+
if (hashIndex === -1) {
|
|
26
|
+
return { path: input };
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
path: input.slice(0, hashIndex),
|
|
30
|
+
anchor: input.slice(hashIndex + 1),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function fetchMarkdown(
|
|
35
|
+
url: string,
|
|
36
|
+
): Promise<{ ok: true; content: string } | { ok: false; error: string }> {
|
|
37
|
+
try {
|
|
38
|
+
const response = await fetch(url);
|
|
39
|
+
if (response.status === 404) {
|
|
40
|
+
return { ok: false, error: `Documentation not found: ${url}` };
|
|
41
|
+
}
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
error: `Failed to fetch documentation: ${response.status}`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const content = await response.text();
|
|
49
|
+
return { ok: true, content };
|
|
50
|
+
} catch (error) {
|
|
51
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
52
|
+
return { ok: false, error: `Network error: ${message}` };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function anchorToHeadingPattern(anchor: string): RegExp {
|
|
57
|
+
// Convert kebab-case anchor to a pattern that matches the heading text.
|
|
58
|
+
const pattern = anchor
|
|
59
|
+
.split("-")
|
|
60
|
+
.map((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
|
|
61
|
+
.join("[\\s-]+");
|
|
62
|
+
return new RegExp(`^(#{1,6})\\s+${pattern}\\s*$`, "im");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function extractSection(
|
|
66
|
+
markdown: string,
|
|
67
|
+
anchor: string,
|
|
68
|
+
): { ok: true; content: string } | { ok: false; error: string } {
|
|
69
|
+
const lines = markdown.split("\n");
|
|
70
|
+
const headingPattern = anchorToHeadingPattern(anchor);
|
|
71
|
+
|
|
72
|
+
let startIndex = -1;
|
|
73
|
+
let headingLevel = 0;
|
|
74
|
+
|
|
75
|
+
for (let i = 0; i < lines.length; i++) {
|
|
76
|
+
const match = lines[i].match(headingPattern);
|
|
77
|
+
if (match) {
|
|
78
|
+
startIndex = i;
|
|
79
|
+
headingLevel = match[1].length;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (startIndex === -1) {
|
|
85
|
+
return { ok: false, error: `Anchor not found: #${anchor}` };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let endIndex = lines.length;
|
|
89
|
+
for (let i = startIndex + 1; i < lines.length; i++) {
|
|
90
|
+
const headingMatch = lines[i].match(/^(#{1,6})\s/);
|
|
91
|
+
if (headingMatch && headingMatch[1].length <= headingLevel) {
|
|
92
|
+
endIndex = i;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const content = lines.slice(startIndex, endIndex).join("\n").trim();
|
|
98
|
+
return { ok: true, content };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function docsFetch(): Promise<void> {
|
|
102
|
+
const {
|
|
103
|
+
positionals: [pathArg],
|
|
104
|
+
values: { help },
|
|
105
|
+
} = parseArgs({
|
|
106
|
+
args: process.argv.slice(4),
|
|
107
|
+
options: {
|
|
108
|
+
help: { type: "boolean", short: "h" },
|
|
109
|
+
},
|
|
110
|
+
allowPositionals: true,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
if (help) {
|
|
114
|
+
console.info(HELP);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!pathArg) {
|
|
119
|
+
console.info(HELP);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const { path, anchor } = parsePathAndAnchor(pathArg);
|
|
124
|
+
const url = `https://prismic.io/docs/${path}.md`;
|
|
125
|
+
|
|
126
|
+
const fetchResult = await fetchMarkdown(url);
|
|
127
|
+
if (!fetchResult.ok) {
|
|
128
|
+
console.error(fetchResult.error);
|
|
129
|
+
process.exitCode = 1;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let output = fetchResult.content;
|
|
134
|
+
|
|
135
|
+
if (anchor) {
|
|
136
|
+
const extractResult = extractSection(output, anchor);
|
|
137
|
+
if (!extractResult.ok) {
|
|
138
|
+
console.error(extractResult.error);
|
|
139
|
+
process.exitCode = 1;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
output = extractResult.content;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.info(output);
|
|
146
|
+
}
|
package/src/docs-list.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
|
|
3
|
+
const HELP = `
|
|
4
|
+
List documentation pages from Prismic's docs site.
|
|
5
|
+
|
|
6
|
+
USAGE
|
|
7
|
+
prismic docs list [flags]
|
|
8
|
+
|
|
9
|
+
FLAGS
|
|
10
|
+
-h, --help Show help for command
|
|
11
|
+
|
|
12
|
+
EXAMPLES
|
|
13
|
+
prismic docs list
|
|
14
|
+
`.trim();
|
|
15
|
+
|
|
16
|
+
const ROOT_SITEMAP_URL = "https://prismic.io/docs/sitemap.xml";
|
|
17
|
+
|
|
18
|
+
function decodeXmlEntities(input: string): string {
|
|
19
|
+
return input
|
|
20
|
+
.replaceAll("&", "&")
|
|
21
|
+
.replaceAll("<", "<")
|
|
22
|
+
.replaceAll(">", ">")
|
|
23
|
+
.replaceAll(""", '"')
|
|
24
|
+
.replaceAll("'", "'");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function extractLocEntries(xml: string): string[] {
|
|
28
|
+
const locPattern = /<loc>(.*?)<\/loc>/g;
|
|
29
|
+
const entries: string[] = [];
|
|
30
|
+
let match = locPattern.exec(xml);
|
|
31
|
+
|
|
32
|
+
while (match) {
|
|
33
|
+
entries.push(decodeXmlEntities(match[1]).trim());
|
|
34
|
+
match = locPattern.exec(xml);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return entries.filter(Boolean);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function fetchXml(url: string): Promise<{ ok: true; xml: string } | { ok: false; error: string }> {
|
|
41
|
+
try {
|
|
42
|
+
const response = await fetch(url);
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
error: `Failed to fetch sitemap: ${response.status} (${url})`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
ok: true,
|
|
52
|
+
xml: await response.text(),
|
|
53
|
+
};
|
|
54
|
+
} catch (error) {
|
|
55
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
56
|
+
return { ok: false, error: `Network error while fetching sitemap ${url}: ${message}` };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function toDocsPath(urlString: string): string | null {
|
|
61
|
+
try {
|
|
62
|
+
const url = new URL(urlString);
|
|
63
|
+
if (url.hostname !== "prismic.io") {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!url.pathname.startsWith("/docs/")) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return url.pathname.replace(/^\/docs\//, "").replace(/^\/+|\/+$/g, "");
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function docsList(): Promise<void> {
|
|
78
|
+
const {
|
|
79
|
+
values: { help },
|
|
80
|
+
} = parseArgs({
|
|
81
|
+
args: process.argv.slice(4),
|
|
82
|
+
options: {
|
|
83
|
+
help: { type: "boolean", short: "h" },
|
|
84
|
+
},
|
|
85
|
+
allowPositionals: true,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (help) {
|
|
89
|
+
console.info(HELP);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const rootResult = await fetchXml(ROOT_SITEMAP_URL);
|
|
94
|
+
if (!rootResult.ok) {
|
|
95
|
+
console.error(rootResult.error);
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const nestedSitemapUrls = extractLocEntries(rootResult.xml);
|
|
101
|
+
if (nestedSitemapUrls.length === 0) {
|
|
102
|
+
console.error(`No nested sitemaps found in ${ROOT_SITEMAP_URL}`);
|
|
103
|
+
process.exitCode = 1;
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const nestedResults = await Promise.all(nestedSitemapUrls.map((url) => fetchXml(url)));
|
|
108
|
+
const failedFetch = nestedResults.find((result) => !result.ok);
|
|
109
|
+
if (failedFetch && !failedFetch.ok) {
|
|
110
|
+
console.error(failedFetch.error);
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const paths = new Set<string>();
|
|
116
|
+
|
|
117
|
+
for (const nestedResult of nestedResults) {
|
|
118
|
+
if (!nestedResult.ok) continue;
|
|
119
|
+
|
|
120
|
+
for (const url of extractLocEntries(nestedResult.xml)) {
|
|
121
|
+
const path = toDocsPath(url);
|
|
122
|
+
if (path) {
|
|
123
|
+
paths.add(path);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
for (const path of [...paths].sort((a, b) => a.localeCompare(b))) {
|
|
129
|
+
console.info(path);
|
|
130
|
+
}
|
|
131
|
+
}
|
package/src/docs.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
import { docsFetch } from "./docs-fetch";
|
|
3
|
+
import { docsList } from "./docs-list";
|
|
4
|
+
|
|
5
|
+
const HELP = `
|
|
6
|
+
Fetch and list documentation from Prismic's docs site.
|
|
7
|
+
|
|
8
|
+
USAGE
|
|
9
|
+
prismic docs <command> [flags]
|
|
10
|
+
|
|
11
|
+
COMMANDS
|
|
12
|
+
fetch Fetch and display a documentation page
|
|
13
|
+
list List documentation pages
|
|
14
|
+
|
|
15
|
+
FLAGS
|
|
16
|
+
-h, --help Show help for command
|
|
17
|
+
|
|
18
|
+
EXAMPLES
|
|
19
|
+
prismic docs fetch nextjs
|
|
20
|
+
prismic docs fetch nextjs#set-up-a-prismic-client
|
|
21
|
+
prismic docs list
|
|
22
|
+
|
|
23
|
+
LEARN MORE
|
|
24
|
+
Use \`prismic docs <command> --help\` for more information about a command.
|
|
25
|
+
`.trim();
|
|
26
|
+
|
|
27
|
+
export async function docs(): Promise<void> {
|
|
28
|
+
const {
|
|
29
|
+
positionals: [subcommand],
|
|
30
|
+
} = parseArgs({
|
|
31
|
+
args: process.argv.slice(3),
|
|
32
|
+
options: {
|
|
33
|
+
help: { type: "boolean", short: "h" },
|
|
34
|
+
},
|
|
35
|
+
allowPositionals: true,
|
|
36
|
+
strict: false,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
switch (subcommand) {
|
|
40
|
+
case "fetch":
|
|
41
|
+
await docsFetch();
|
|
42
|
+
break;
|
|
43
|
+
case "list":
|
|
44
|
+
await docsList();
|
|
45
|
+
break;
|
|
46
|
+
default: {
|
|
47
|
+
if (subcommand) {
|
|
48
|
+
console.error(`Unknown docs subcommand: ${subcommand}\n`);
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
}
|
|
51
|
+
console.info(HELP);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
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 { docs } from "./docs";
|
|
9
|
+
import { init } from "./init";
|
|
10
|
+
import { locale } from "./locale";
|
|
11
|
+
import { login } from "./login";
|
|
12
|
+
import { logout } from "./logout";
|
|
13
|
+
import { pageType } from "./page-type";
|
|
14
|
+
import { preview } from "./preview";
|
|
15
|
+
import { pull } from "./pull";
|
|
16
|
+
import { push } from "./push";
|
|
17
|
+
import { repo } from "./repo";
|
|
18
|
+
import { slice } from "./slice";
|
|
19
|
+
import { status } from "./status";
|
|
20
|
+
import { token } from "./token";
|
|
21
|
+
import { webhook } from "./webhook";
|
|
22
|
+
import { whoami } from "./whoami";
|
|
23
|
+
|
|
24
|
+
const HELP = `
|
|
25
|
+
Prismic CLI for managing repositories and configurations.
|
|
26
|
+
|
|
27
|
+
USAGE
|
|
28
|
+
prismic <command> [flags]
|
|
29
|
+
|
|
30
|
+
COMMANDS
|
|
31
|
+
init Initialize a Prismic project
|
|
32
|
+
login Log in to Prismic
|
|
33
|
+
logout Log out of Prismic
|
|
34
|
+
whoami Show the currently logged in user
|
|
35
|
+
status Show the status of the current project
|
|
36
|
+
repo Manage Prismic repositories
|
|
37
|
+
locale Manage locales in a repository
|
|
38
|
+
page-type Manage page types in a repository
|
|
39
|
+
custom-type Manage custom types in a repository
|
|
40
|
+
slice Manage slices in a project
|
|
41
|
+
pull Pull types and slices from Prismic
|
|
42
|
+
push Push types and slices to Prismic
|
|
43
|
+
codegen Generate code from Prismic models
|
|
44
|
+
docs Fetch and list documentation from Prismic
|
|
45
|
+
preview Manage preview configurations
|
|
46
|
+
token Manage API tokens in a repository
|
|
47
|
+
webhook Manage webhooks in a repository
|
|
48
|
+
|
|
49
|
+
FLAGS
|
|
50
|
+
-v, --version Show CLI version
|
|
51
|
+
-h, --help Show help for command
|
|
52
|
+
|
|
53
|
+
LEARN MORE
|
|
54
|
+
Use \`prismic <command> --help\` for more information about a command.
|
|
55
|
+
`.trim();
|
|
56
|
+
|
|
57
|
+
const {
|
|
58
|
+
positionals,
|
|
59
|
+
values: { version },
|
|
60
|
+
} = parseArgs({
|
|
61
|
+
options: {
|
|
62
|
+
help: { type: "boolean", short: "h" },
|
|
63
|
+
version: { type: "boolean", short: "v" },
|
|
64
|
+
},
|
|
65
|
+
allowPositionals: true,
|
|
66
|
+
strict: false,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
if (version) {
|
|
70
|
+
console.info(packageJson.version);
|
|
71
|
+
} else {
|
|
72
|
+
switch (positionals[0]) {
|
|
73
|
+
case "init":
|
|
74
|
+
await init();
|
|
75
|
+
break;
|
|
76
|
+
case "login":
|
|
77
|
+
await login();
|
|
78
|
+
break;
|
|
79
|
+
case "logout":
|
|
80
|
+
await logout();
|
|
81
|
+
break;
|
|
82
|
+
case "whoami":
|
|
83
|
+
await whoami();
|
|
84
|
+
break;
|
|
85
|
+
case "status":
|
|
86
|
+
await status();
|
|
87
|
+
break;
|
|
88
|
+
case "repo":
|
|
89
|
+
await repo();
|
|
90
|
+
break;
|
|
91
|
+
case "locale":
|
|
92
|
+
await locale();
|
|
93
|
+
break;
|
|
94
|
+
case "page-type":
|
|
95
|
+
await pageType();
|
|
96
|
+
break;
|
|
97
|
+
case "custom-type":
|
|
98
|
+
await customType();
|
|
99
|
+
break;
|
|
100
|
+
case "slice":
|
|
101
|
+
await slice();
|
|
102
|
+
break;
|
|
103
|
+
case "pull":
|
|
104
|
+
await pull();
|
|
105
|
+
break;
|
|
106
|
+
case "push":
|
|
107
|
+
await push();
|
|
108
|
+
break;
|
|
109
|
+
case "codegen":
|
|
110
|
+
await codegen();
|
|
111
|
+
break;
|
|
112
|
+
case "docs":
|
|
113
|
+
await docs();
|
|
114
|
+
break;
|
|
115
|
+
case "preview":
|
|
116
|
+
await preview();
|
|
117
|
+
break;
|
|
118
|
+
case "token":
|
|
119
|
+
await token();
|
|
120
|
+
break;
|
|
121
|
+
case "webhook":
|
|
122
|
+
await webhook();
|
|
123
|
+
break;
|
|
124
|
+
default: {
|
|
125
|
+
if (positionals[0]) {
|
|
126
|
+
console.error(`Unknown command: ${positionals[0]}`);
|
|
127
|
+
process.exitCode = 1;
|
|
128
|
+
}
|
|
129
|
+
console.info(HELP);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
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
|
+
}
|