@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.
Files changed (139) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +98 -0
  3. package/dist/index.mjs +2508 -0
  4. package/package.json +53 -0
  5. package/src/codegen-types.ts +82 -0
  6. package/src/codegen.ts +45 -0
  7. package/src/custom-type-add-field-boolean.ts +222 -0
  8. package/src/custom-type-add-field-color.ts +205 -0
  9. package/src/custom-type-add-field-date.ts +208 -0
  10. package/src/custom-type-add-field-embed.ts +205 -0
  11. package/src/custom-type-add-field-geo-point.ts +202 -0
  12. package/src/custom-type-add-field-group.ts +179 -0
  13. package/src/custom-type-add-field-image.ts +205 -0
  14. package/src/custom-type-add-field-key-text.ts +205 -0
  15. package/src/custom-type-add-field-link.ts +228 -0
  16. package/src/custom-type-add-field-number.ts +237 -0
  17. package/src/custom-type-add-field-rich-text.ts +229 -0
  18. package/src/custom-type-add-field-select.ts +211 -0
  19. package/src/custom-type-add-field-timestamp.ts +208 -0
  20. package/src/custom-type-add-field-uid.ts +188 -0
  21. package/src/custom-type-add-field.ts +116 -0
  22. package/src/custom-type-connect-slice.ts +214 -0
  23. package/src/custom-type-create.ts +112 -0
  24. package/src/custom-type-disconnect-slice.ts +171 -0
  25. package/src/custom-type-list.ts +110 -0
  26. package/src/custom-type-remove-field.ts +171 -0
  27. package/src/custom-type-remove.ts +138 -0
  28. package/src/custom-type-set-name.ts +138 -0
  29. package/src/custom-type-view.ts +118 -0
  30. package/src/custom-type.ts +85 -0
  31. package/src/docs-fetch.ts +146 -0
  32. package/src/docs-list.ts +131 -0
  33. package/src/docs.ts +54 -0
  34. package/src/index.ts +132 -0
  35. package/src/init.ts +64 -0
  36. package/src/lib/auth.ts +83 -0
  37. package/src/lib/config.ts +111 -0
  38. package/src/lib/custom-types-api.ts +438 -0
  39. package/src/lib/field-path.ts +81 -0
  40. package/src/lib/file.ts +49 -0
  41. package/src/lib/framework.ts +143 -0
  42. package/src/lib/json.ts +3 -0
  43. package/src/lib/request.ts +116 -0
  44. package/src/lib/slice.ts +115 -0
  45. package/src/lib/string.ts +6 -0
  46. package/src/lib/url.ts +25 -0
  47. package/src/locale-add.ts +116 -0
  48. package/src/locale-list.ts +107 -0
  49. package/src/locale-remove.ts +88 -0
  50. package/src/locale-set-default.ts +131 -0
  51. package/src/locale.ts +60 -0
  52. package/src/login.ts +152 -0
  53. package/src/logout.ts +36 -0
  54. package/src/page-type-add-field-boolean.ts +238 -0
  55. package/src/page-type-add-field-color.ts +224 -0
  56. package/src/page-type-add-field-date.ts +227 -0
  57. package/src/page-type-add-field-embed.ts +224 -0
  58. package/src/page-type-add-field-geo-point.ts +221 -0
  59. package/src/page-type-add-field-group.ts +198 -0
  60. package/src/page-type-add-field-image.ts +224 -0
  61. package/src/page-type-add-field-key-text.ts +224 -0
  62. package/src/page-type-add-field-link.ts +247 -0
  63. package/src/page-type-add-field-number.ts +256 -0
  64. package/src/page-type-add-field-rich-text.ts +248 -0
  65. package/src/page-type-add-field-select.ts +230 -0
  66. package/src/page-type-add-field-timestamp.ts +227 -0
  67. package/src/page-type-add-field-uid.ts +207 -0
  68. package/src/page-type-add-field.ts +116 -0
  69. package/src/page-type-connect-slice.ts +214 -0
  70. package/src/page-type-create.ts +161 -0
  71. package/src/page-type-disconnect-slice.ts +171 -0
  72. package/src/page-type-list.ts +109 -0
  73. package/src/page-type-remove-field.ts +171 -0
  74. package/src/page-type-remove.ts +138 -0
  75. package/src/page-type-set-name.ts +138 -0
  76. package/src/page-type-set-repeatable.ts +147 -0
  77. package/src/page-type-view.ts +118 -0
  78. package/src/page-type.ts +90 -0
  79. package/src/preview-add.ts +126 -0
  80. package/src/preview-get-simulator.ts +104 -0
  81. package/src/preview-list.ts +106 -0
  82. package/src/preview-remove-simulator.ts +80 -0
  83. package/src/preview-remove.ts +109 -0
  84. package/src/preview-set-name.ts +137 -0
  85. package/src/preview-set-simulator.ts +116 -0
  86. package/src/preview.ts +75 -0
  87. package/src/pull.ts +242 -0
  88. package/src/push.ts +405 -0
  89. package/src/repo-create.ts +195 -0
  90. package/src/repo-get-access.ts +86 -0
  91. package/src/repo-list.ts +100 -0
  92. package/src/repo-set-access.ts +100 -0
  93. package/src/repo-set-name.ts +102 -0
  94. package/src/repo-view.ts +113 -0
  95. package/src/repo.ts +70 -0
  96. package/src/slice-add-field-boolean.ts +240 -0
  97. package/src/slice-add-field-color.ts +226 -0
  98. package/src/slice-add-field-date.ts +226 -0
  99. package/src/slice-add-field-embed.ts +226 -0
  100. package/src/slice-add-field-geo-point.ts +223 -0
  101. package/src/slice-add-field-group.ts +191 -0
  102. package/src/slice-add-field-image.ts +223 -0
  103. package/src/slice-add-field-key-text.ts +226 -0
  104. package/src/slice-add-field-link.ts +245 -0
  105. package/src/slice-add-field-number.ts +226 -0
  106. package/src/slice-add-field-rich-text.ts +250 -0
  107. package/src/slice-add-field-select.ts +232 -0
  108. package/src/slice-add-field-timestamp.ts +226 -0
  109. package/src/slice-add-field.ts +111 -0
  110. package/src/slice-add-variation.ts +139 -0
  111. package/src/slice-create.ts +203 -0
  112. package/src/slice-list-variations.ts +67 -0
  113. package/src/slice-list.ts +88 -0
  114. package/src/slice-remove-field.ts +122 -0
  115. package/src/slice-remove-variation.ts +112 -0
  116. package/src/slice-remove.ts +91 -0
  117. package/src/slice-rename.ts +122 -0
  118. package/src/slice-set-screenshot.ts +235 -0
  119. package/src/slice-view.ts +80 -0
  120. package/src/slice.ts +95 -0
  121. package/src/status.ts +873 -0
  122. package/src/token-create.ts +203 -0
  123. package/src/token-delete.ts +182 -0
  124. package/src/token-list.ts +223 -0
  125. package/src/token-set-name.ts +193 -0
  126. package/src/token.ts +60 -0
  127. package/src/webhook-add-header.ts +118 -0
  128. package/src/webhook-create.ts +152 -0
  129. package/src/webhook-disable.ts +109 -0
  130. package/src/webhook-enable.ts +132 -0
  131. package/src/webhook-list.ts +93 -0
  132. package/src/webhook-remove-header.ts +117 -0
  133. package/src/webhook-remove.ts +106 -0
  134. package/src/webhook-set-triggers.ts +148 -0
  135. package/src/webhook-status.ts +90 -0
  136. package/src/webhook-test.ts +106 -0
  137. package/src/webhook-view.ts +147 -0
  138. package/src/webhook.ts +95 -0
  139. 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
+ }
@@ -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("&amp;", "&")
21
+ .replaceAll("&lt;", "<")
22
+ .replaceAll("&gt;", ">")
23
+ .replaceAll("&quot;", '"')
24
+ .replaceAll("&apos;", "'");
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
+ }
@@ -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
+ }