@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,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 page type.
11
+
12
+ USAGE
13
+ prismic page-type view <type-id> [flags]
14
+
15
+ ARGUMENTS
16
+ type-id Page type identifier (required)
17
+
18
+ FLAGS
19
+ --json Output as JSON
20
+ -h, --help Show help for command
21
+
22
+ EXAMPLES
23
+ prismic page-type view homepage
24
+ prismic page-type view homepage --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 pageTypeView(): Promise<void> {
37
+ const {
38
+ values: { help, json },
39
+ positionals: [typeId],
40
+ } = parseArgs({
41
+ args: process.argv.slice(4), // skip: node, script, "page-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 page-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 page 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(`Page type not found: ${typeId}\n`);
83
+ console.error(`Create it first with: prismic page-type create ${typeId}`);
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+ if (error instanceof Error) {
88
+ console.error(`Failed to read page type: ${error.message}`);
89
+ } else {
90
+ console.error("Failed to read page type");
91
+ }
92
+ process.exitCode = 1;
93
+ return;
94
+ }
95
+
96
+ // Check if this is actually a page type
97
+ if (model.format !== "page") {
98
+ console.error(`"${typeId}" is not a page type (format: ${model.format ?? "custom"})`);
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,90 @@
1
+ import { parseArgs } from "node:util";
2
+
3
+ import { pageTypeAddField } from "./page-type-add-field";
4
+ import { pageTypeConnectSlice } from "./page-type-connect-slice";
5
+ import { pageTypeCreate } from "./page-type-create";
6
+ import { pageTypeDisconnectSlice } from "./page-type-disconnect-slice";
7
+ import { pageTypeList } from "./page-type-list";
8
+ import { pageTypeRemove } from "./page-type-remove";
9
+ import { pageTypeRemoveField } from "./page-type-remove-field";
10
+ import { pageTypeSetName } from "./page-type-set-name";
11
+ import { pageTypeSetRepeatable } from "./page-type-set-repeatable";
12
+ import { pageTypeView } from "./page-type-view";
13
+
14
+ const HELP = `
15
+ Manage page types in a Prismic repository.
16
+
17
+ USAGE
18
+ prismic page-type <command> [flags]
19
+
20
+ COMMANDS
21
+ create Create a new page type
22
+ list List all page types
23
+ view View details of a page type
24
+ remove Remove a page type
25
+ set-name Change a page type's display name
26
+ set-repeatable Set whether a page type is repeatable
27
+ add-field Add a field to a page type
28
+ remove-field Remove a field from a page type
29
+ connect-slice Connect a shared slice to a page type
30
+ disconnect-slice Disconnect a shared slice from a page type
31
+
32
+ FLAGS
33
+ -h, --help Show help for command
34
+
35
+ LEARN MORE
36
+ Use \`prismic page-type <command> --help\` for more information about a command.
37
+ `.trim();
38
+
39
+ export async function pageType(): Promise<void> {
40
+ const {
41
+ positionals: [subcommand],
42
+ } = parseArgs({
43
+ args: process.argv.slice(3), // skip: node, script, "page-type"
44
+ options: {
45
+ help: { type: "boolean", short: "h" },
46
+ },
47
+ allowPositionals: true,
48
+ strict: false,
49
+ });
50
+
51
+ switch (subcommand) {
52
+ case "create":
53
+ await pageTypeCreate();
54
+ break;
55
+ case "list":
56
+ await pageTypeList();
57
+ break;
58
+ case "view":
59
+ await pageTypeView();
60
+ break;
61
+ case "remove":
62
+ await pageTypeRemove();
63
+ break;
64
+ case "set-name":
65
+ await pageTypeSetName();
66
+ break;
67
+ case "set-repeatable":
68
+ await pageTypeSetRepeatable();
69
+ break;
70
+ case "add-field":
71
+ await pageTypeAddField();
72
+ break;
73
+ case "remove-field":
74
+ await pageTypeRemoveField();
75
+ break;
76
+ case "connect-slice":
77
+ await pageTypeConnectSlice();
78
+ break;
79
+ case "disconnect-slice":
80
+ await pageTypeDisconnectSlice();
81
+ break;
82
+ default: {
83
+ if (subcommand) {
84
+ console.error(`Unknown page-type subcommand: ${subcommand}\n`);
85
+ process.exitCode = 1;
86
+ }
87
+ console.info(HELP);
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,126 @@
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 preview configuration 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 preview add <url> [flags]
17
+
18
+ ARGUMENTS
19
+ <url> Preview URL (e.g. https://example.com/api/preview)
20
+
21
+ FLAGS
22
+ -n, --name string Display name (defaults to hostname)
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 previewAdd(): Promise<void> {
31
+ const {
32
+ values: { help, name, repo = await safeGetRepositoryFromConfig() },
33
+ positionals: [previewUrl],
34
+ } = parseArgs({
35
+ args: process.argv.slice(4), // skip: node, script, "preview", "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 (!previewUrl) {
50
+ console.error("Missing required argument: <url>");
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 parsed = parsePreviewUrl(previewUrl);
68
+ if (!parsed) {
69
+ console.error(`Invalid URL: ${previewUrl}`);
70
+ process.exitCode = 1;
71
+ return;
72
+ }
73
+
74
+ const displayName = name || parsed.hostname;
75
+
76
+ const response = await addPreview(repo, {
77
+ name: displayName,
78
+ websiteURL: parsed.websiteURL,
79
+ resolverPath: parsed.resolverPath,
80
+ });
81
+
82
+ if (!response.ok) {
83
+ if (response.error instanceof ForbiddenRequestError) {
84
+ handleUnauthenticated();
85
+ } else {
86
+ console.error(`Failed to add preview: ${stringify(response.value)}`);
87
+ process.exitCode = 1;
88
+ }
89
+ return;
90
+ }
91
+
92
+ console.info(`Preview added: ${previewUrl}`);
93
+ }
94
+
95
+ export function parsePreviewUrl(
96
+ url: string,
97
+ ): { websiteURL: string; resolverPath: string | undefined; hostname: string } | undefined {
98
+ try {
99
+ const parsed = new URL(url);
100
+ const websiteURL = `${parsed.protocol}//${parsed.host}`;
101
+ const resolverPath = parsed.pathname === "/" ? undefined : parsed.pathname;
102
+ return { websiteURL, resolverPath, hostname: parsed.hostname };
103
+ } catch {
104
+ return undefined;
105
+ }
106
+ }
107
+
108
+ async function addPreview(
109
+ repo: string,
110
+ config: { name: string; websiteURL: string; resolverPath: string | undefined },
111
+ ) {
112
+ const url = new URL("/previews/new", await getRepoUrl(repo));
113
+ return await request(url, {
114
+ method: "POST",
115
+ body: {
116
+ name: config.name,
117
+ websiteURL: config.websiteURL,
118
+ resolverPath: config.resolverPath,
119
+ },
120
+ });
121
+ }
122
+
123
+ function handleUnauthenticated() {
124
+ console.error("Not logged in. Run `prismic login` first.");
125
+ process.exitCode = 1;
126
+ }
@@ -0,0 +1,104 @@
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 { getRepoUrl } from "./lib/url";
9
+
10
+ const HELP = `
11
+ Show the slice simulator URL for 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 preview get-simulator [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 previewGetSimulator(): Promise<void> {
29
+ const {
30
+ values: { help, repo = await safeGetRepositoryFromConfig(), json },
31
+ } = parseArgs({
32
+ args: process.argv.slice(4), // skip: node, script, "preview", "get-simulator"
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 getSimulatorUrl(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 get simulator URL: Invalid response: ${stringify(response.error.issues)}`,
65
+ );
66
+ process.exitCode = 1;
67
+ } else {
68
+ console.error(`Failed to get simulator URL: ${stringify(response.value)}`);
69
+ process.exitCode = 1;
70
+ }
71
+ return;
72
+ }
73
+
74
+ const simulatorUrl = response.value.simulator_url;
75
+ if (!simulatorUrl) {
76
+ if (json) {
77
+ console.info(stringify({ simulator_url: null }));
78
+ } else {
79
+ console.info("No simulator URL configured.");
80
+ }
81
+ return;
82
+ }
83
+
84
+ if (json) {
85
+ console.info(stringify({ simulator_url: simulatorUrl }));
86
+ } else {
87
+ console.info(simulatorUrl);
88
+ }
89
+ }
90
+
91
+ const RepositoryResponseSchema = v.object({
92
+ simulator_url: v.optional(v.string()),
93
+ });
94
+ type RepositoryResponse = v.InferOutput<typeof RepositoryResponseSchema>;
95
+
96
+ async function getSimulatorUrl(repo: string): Promise<ParsedRequestResponse<RepositoryResponse>> {
97
+ const url = new URL("/core/repository", await getRepoUrl(repo));
98
+ return await request(url, { schema: RepositoryResponseSchema });
99
+ }
100
+
101
+ function handleUnauthenticated() {
102
+ console.error("Not logged in. Run `prismic login` first.");
103
+ process.exitCode = 1;
104
+ }
@@ -0,0 +1,106 @@
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 { getRepoUrl } from "./lib/url";
9
+
10
+ const HELP = `
11
+ List all preview configurations 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 preview 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 previewList(): Promise<void> {
29
+ const {
30
+ values: { help, repo = await safeGetRepositoryFromConfig(), json },
31
+ } = parseArgs({
32
+ args: process.argv.slice(4), // skip: node, script, "preview", "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 getPreviews(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 previews: Invalid response: ${stringify(response.error.issues)}`,
65
+ );
66
+ process.exitCode = 1;
67
+ } else {
68
+ console.error(`Failed to list previews: ${stringify(response.value)}`);
69
+ process.exitCode = 1;
70
+ }
71
+ return;
72
+ }
73
+
74
+ const previews = response.value.results;
75
+ if (json) {
76
+ console.info(stringify(previews));
77
+ } else {
78
+ for (const preview of previews) {
79
+ console.info(`${preview.url} ${preview.label}`);
80
+ }
81
+ }
82
+ }
83
+
84
+ const PreviewSchema = v.object({
85
+ id: v.string(),
86
+ label: v.string(),
87
+ url: v.string(),
88
+ });
89
+ export type Preview = v.InferOutput<typeof PreviewSchema>;
90
+
91
+ const GetPreviewsResponseSchema = v.object({
92
+ results: v.array(PreviewSchema),
93
+ });
94
+ type GetPreviewsResponse = v.InferOutput<typeof GetPreviewsResponseSchema>;
95
+
96
+ export async function getPreviews(
97
+ repo: string,
98
+ ): Promise<ParsedRequestResponse<GetPreviewsResponse>> {
99
+ const url = new URL("/core/repository/preview_configs", await getRepoUrl(repo));
100
+ return await request(url, { schema: GetPreviewsResponseSchema });
101
+ }
102
+
103
+ function handleUnauthenticated() {
104
+ console.error("Not logged in. Run `prismic login` first.");
105
+ process.exitCode = 1;
106
+ }
@@ -0,0 +1,80 @@
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
+ Remove the slice simulator URL 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 preview remove-simulator [flags]
17
+
18
+ FLAGS
19
+ -r, --repo string Repository domain
20
+ -h, --help Show help for command
21
+
22
+ LEARN MORE
23
+ Use \`prismic <command> <subcommand> --help\` for more information about a command.
24
+ `.trim();
25
+
26
+ export async function previewRemoveSimulator(): Promise<void> {
27
+ const {
28
+ values: { help, repo = await safeGetRepositoryFromConfig() },
29
+ } = parseArgs({
30
+ args: process.argv.slice(4), // skip: node, script, "preview", "remove-simulator"
31
+ options: {
32
+ repo: { type: "string", short: "r" },
33
+ help: { type: "boolean", short: "h" },
34
+ },
35
+ allowPositionals: false,
36
+ });
37
+
38
+ if (help) {
39
+ console.info(HELP);
40
+ return;
41
+ }
42
+
43
+ if (!repo) {
44
+ console.error("Missing prismic.config.json or --repo option");
45
+ process.exitCode = 1;
46
+ return;
47
+ }
48
+
49
+ const authenticated = await isAuthenticated();
50
+ if (!authenticated) {
51
+ handleUnauthenticated();
52
+ return;
53
+ }
54
+
55
+ const response = await removeSimulatorUrl(repo);
56
+ if (!response.ok) {
57
+ if (response.error instanceof ForbiddenRequestError) {
58
+ handleUnauthenticated();
59
+ } else {
60
+ console.error(`Failed to remove simulator URL: ${stringify(response.value)}`);
61
+ process.exitCode = 1;
62
+ }
63
+ return;
64
+ }
65
+
66
+ console.info("Simulator URL removed.");
67
+ }
68
+
69
+ async function removeSimulatorUrl(repo: string) {
70
+ const url = new URL("/core/repository", await getRepoUrl(repo));
71
+ return await request(url, {
72
+ method: "PATCH",
73
+ body: { simulator_url: "" },
74
+ });
75
+ }
76
+
77
+ function handleUnauthenticated() {
78
+ console.error("Not logged in. Run `prismic login` first.");
79
+ process.exitCode = 1;
80
+ }