@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.
Files changed (131) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +98 -0
  3. package/dist/index.mjs +2548 -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 +192 -0
  8. package/src/custom-type-add-field-color.ts +177 -0
  9. package/src/custom-type-add-field-date.ts +180 -0
  10. package/src/custom-type-add-field-embed.ts +177 -0
  11. package/src/custom-type-add-field-geo-point.ts +174 -0
  12. package/src/custom-type-add-field-image.ts +177 -0
  13. package/src/custom-type-add-field-key-text.ts +177 -0
  14. package/src/custom-type-add-field-link.ts +201 -0
  15. package/src/custom-type-add-field-number.ts +209 -0
  16. package/src/custom-type-add-field-rich-text.ts +202 -0
  17. package/src/custom-type-add-field-select.ts +192 -0
  18. package/src/custom-type-add-field-timestamp.ts +180 -0
  19. package/src/custom-type-add-field-uid.ts +177 -0
  20. package/src/custom-type-add-field.ts +111 -0
  21. package/src/custom-type-connect-slice.ts +220 -0
  22. package/src/custom-type-create.ts +118 -0
  23. package/src/custom-type-disconnect-slice.ts +177 -0
  24. package/src/custom-type-list.ts +110 -0
  25. package/src/custom-type-remove-field.ts +177 -0
  26. package/src/custom-type-remove.ts +144 -0
  27. package/src/custom-type-set-name.ts +144 -0
  28. package/src/custom-type-view.ts +118 -0
  29. package/src/custom-type.ts +85 -0
  30. package/src/index.ts +127 -0
  31. package/src/init.ts +64 -0
  32. package/src/lib/auth.ts +83 -0
  33. package/src/lib/config.ts +111 -0
  34. package/src/lib/custom-types-api.ts +438 -0
  35. package/src/lib/file.ts +49 -0
  36. package/src/lib/framework.ts +143 -0
  37. package/src/lib/json.ts +3 -0
  38. package/src/lib/request.ts +116 -0
  39. package/src/lib/slice.ts +115 -0
  40. package/src/lib/string.ts +6 -0
  41. package/src/lib/url.ts +25 -0
  42. package/src/locale-add.ts +116 -0
  43. package/src/locale-list.ts +107 -0
  44. package/src/locale-remove.ts +88 -0
  45. package/src/locale-set-default.ts +131 -0
  46. package/src/locale.ts +60 -0
  47. package/src/login.ts +152 -0
  48. package/src/logout.ts +36 -0
  49. package/src/page-type-add-field-boolean.ts +192 -0
  50. package/src/page-type-add-field-color.ts +177 -0
  51. package/src/page-type-add-field-date.ts +180 -0
  52. package/src/page-type-add-field-embed.ts +177 -0
  53. package/src/page-type-add-field-geo-point.ts +174 -0
  54. package/src/page-type-add-field-image.ts +177 -0
  55. package/src/page-type-add-field-key-text.ts +177 -0
  56. package/src/page-type-add-field-link.ts +201 -0
  57. package/src/page-type-add-field-number.ts +209 -0
  58. package/src/page-type-add-field-rich-text.ts +202 -0
  59. package/src/page-type-add-field-select.ts +192 -0
  60. package/src/page-type-add-field-timestamp.ts +180 -0
  61. package/src/page-type-add-field-uid.ts +177 -0
  62. package/src/page-type-add-field.ts +111 -0
  63. package/src/page-type-connect-slice.ts +220 -0
  64. package/src/page-type-create.ts +142 -0
  65. package/src/page-type-disconnect-slice.ts +177 -0
  66. package/src/page-type-list.ts +109 -0
  67. package/src/page-type-remove-field.ts +177 -0
  68. package/src/page-type-remove.ts +144 -0
  69. package/src/page-type-set-name.ts +144 -0
  70. package/src/page-type-set-repeatable.ts +153 -0
  71. package/src/page-type-view.ts +118 -0
  72. package/src/page-type.ts +90 -0
  73. package/src/preview-add.ts +126 -0
  74. package/src/preview-get-simulator.ts +104 -0
  75. package/src/preview-list.ts +106 -0
  76. package/src/preview-remove-simulator.ts +80 -0
  77. package/src/preview-remove.ts +109 -0
  78. package/src/preview-set-name.ts +137 -0
  79. package/src/preview-set-simulator.ts +116 -0
  80. package/src/preview.ts +75 -0
  81. package/src/pull.ts +247 -0
  82. package/src/push.ts +405 -0
  83. package/src/repo-create.ts +136 -0
  84. package/src/repo-get-access.ts +86 -0
  85. package/src/repo-list.ts +100 -0
  86. package/src/repo-set-access.ts +100 -0
  87. package/src/repo-set-name.ts +102 -0
  88. package/src/repo-view.ts +113 -0
  89. package/src/repo.ts +70 -0
  90. package/src/slice-add-field-boolean.ts +173 -0
  91. package/src/slice-add-field-color.ts +158 -0
  92. package/src/slice-add-field-date.ts +158 -0
  93. package/src/slice-add-field-embed.ts +158 -0
  94. package/src/slice-add-field-geo-point.ts +155 -0
  95. package/src/slice-add-field-image.ts +155 -0
  96. package/src/slice-add-field-key-text.ts +158 -0
  97. package/src/slice-add-field-link.ts +178 -0
  98. package/src/slice-add-field-number.ts +158 -0
  99. package/src/slice-add-field-rich-text.ts +183 -0
  100. package/src/slice-add-field-select.ts +173 -0
  101. package/src/slice-add-field-timestamp.ts +158 -0
  102. package/src/slice-add-field.ts +106 -0
  103. package/src/slice-add-variation.ts +145 -0
  104. package/src/slice-create.ts +148 -0
  105. package/src/slice-list-variations.ts +67 -0
  106. package/src/slice-list.ts +88 -0
  107. package/src/slice-remove-field.ts +128 -0
  108. package/src/slice-remove-variation.ts +118 -0
  109. package/src/slice-remove.ts +97 -0
  110. package/src/slice-rename.ts +128 -0
  111. package/src/slice-view.ts +77 -0
  112. package/src/slice.ts +90 -0
  113. package/src/status.ts +733 -0
  114. package/src/token-create.ts +203 -0
  115. package/src/token-delete.ts +182 -0
  116. package/src/token-list.ts +223 -0
  117. package/src/token-set-name.ts +193 -0
  118. package/src/token.ts +60 -0
  119. package/src/webhook-add-header.ts +118 -0
  120. package/src/webhook-create.ts +152 -0
  121. package/src/webhook-disable.ts +109 -0
  122. package/src/webhook-enable.ts +132 -0
  123. package/src/webhook-list.ts +93 -0
  124. package/src/webhook-remove-header.ts +117 -0
  125. package/src/webhook-remove.ts +106 -0
  126. package/src/webhook-set-triggers.ts +148 -0
  127. package/src/webhook-status.ts +90 -0
  128. package/src/webhook-test.ts +106 -0
  129. package/src/webhook-view.ts +147 -0
  130. package/src/webhook.ts +95 -0
  131. package/src/whoami.ts +62 -0
@@ -0,0 +1,142 @@
1
+ import type { CustomType } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { mkdir, writeFile } from "node:fs/promises";
4
+ import { parseArgs } from "node:util";
5
+
6
+ import { buildTypes } from "./codegen-types";
7
+ import { findUpward } from "./lib/file";
8
+ import { stringify } from "./lib/json";
9
+
10
+ const HELP = `
11
+ Create a new page type in a Prismic repository.
12
+
13
+ USAGE
14
+ prismic page-type create <id> [flags]
15
+
16
+ ARGUMENTS
17
+ id Page type identifier (required)
18
+
19
+ Types are generated by default after changes. Use --no-types to skip.
20
+
21
+ FLAGS
22
+ -n, --name string Display name for the page type
23
+ --single Create as a singleton (non-repeatable) type
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
+ LEARN MORE
29
+ Use \`prismic page-type <command> --help\` for more information about a command.
30
+ `.trim();
31
+
32
+ export async function pageTypeCreate(): Promise<void> {
33
+ const {
34
+ values: { help, name, single, types, "no-types": noTypes },
35
+ positionals: [id],
36
+ } = parseArgs({
37
+ args: process.argv.slice(4), // skip: node, script, "page-type", "create"
38
+ options: {
39
+ name: { type: "string", short: "n" },
40
+ single: { type: "boolean" },
41
+ types: { type: "string" },
42
+ "no-types": { type: "boolean" },
43
+ help: { type: "boolean", short: "h" },
44
+ },
45
+ allowPositionals: true,
46
+ });
47
+
48
+ if (help) {
49
+ console.info(HELP);
50
+ return;
51
+ }
52
+
53
+ if (!id) {
54
+ console.error("Missing required argument: id");
55
+ process.exitCode = 1;
56
+ return;
57
+ }
58
+
59
+ const model = {
60
+ id,
61
+ label: name ?? pascalCase(id),
62
+ repeatable: !single,
63
+ status: true,
64
+ format: "page",
65
+ json: {
66
+ Main: single
67
+ ? {}
68
+ : {
69
+ uid: {
70
+ type: "UID",
71
+ config: { label: "UID", placeholder: "" },
72
+ },
73
+ },
74
+ "SEO & Metadata": {
75
+ meta_title: {
76
+ type: "Text",
77
+ config: {
78
+ label: "Meta Title",
79
+ placeholder: "A title of the page used for social media and search engines",
80
+ },
81
+ },
82
+ meta_description: {
83
+ type: "Text",
84
+ config: {
85
+ label: "Meta Description",
86
+ placeholder: "A brief summary of the page",
87
+ },
88
+ },
89
+ meta_image: {
90
+ type: "Image",
91
+ config: {
92
+ label: "Meta Image",
93
+ constraint: { width: 2400, height: 1260 },
94
+ thumbnails: [],
95
+ },
96
+ },
97
+ },
98
+ },
99
+ } satisfies CustomType;
100
+
101
+ const projectRoot = await findUpward("package.json");
102
+ if (!projectRoot) {
103
+ console.error("Could not find project root (no package.json found)");
104
+ process.exitCode = 1;
105
+ return;
106
+ }
107
+
108
+ const customTypesDirectory = new URL("customtypes/", projectRoot);
109
+ const typeDirectory = new URL(id + "/", customTypesDirectory);
110
+ const modelPath = new URL("index.json", typeDirectory);
111
+
112
+ try {
113
+ await mkdir(new URL(".", modelPath), { recursive: true });
114
+ await writeFile(modelPath, stringify(model));
115
+ } catch (error) {
116
+ if (error instanceof Error) {
117
+ console.error(`Failed to create page type: ${error.message}`);
118
+ } else {
119
+ console.error(`Failed to create page type`);
120
+ }
121
+ process.exitCode = 1;
122
+ return;
123
+ }
124
+
125
+ console.info(`Created page type at ${modelPath.href}`);
126
+
127
+ if (!noTypes) {
128
+ try {
129
+ await buildTypes({ output: types });
130
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
131
+ } catch (error) {
132
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
133
+ }
134
+ }
135
+
136
+ console.info();
137
+ console.info("Next: Add fields with `prismic page-type add-field`");
138
+ }
139
+
140
+ export function pascalCase(input: string): string {
141
+ return input.toLowerCase().replace(/(^|[-_\s]+)(.)?/g, (_, __, c) => c?.toUpperCase() ?? "");
142
+ }
@@ -0,0 +1,177 @@
1
+ import type { CustomType, DynamicSlices } 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
+ Disconnect a shared slice from a page type's slice zone.
13
+
14
+ USAGE
15
+ prismic page-type disconnect-slice <type-id> <slice-id> [flags]
16
+
17
+ ARGUMENTS
18
+ type-id Page type identifier (required)
19
+ slice-id Slice identifier (required)
20
+
21
+ Types are generated by default after changes. Use --no-types to skip.
22
+
23
+ FLAGS
24
+ -z, --slice-zone string Target slice zone field ID (default: "slices")
25
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
26
+ --no-types Skip type generation
27
+ -h, --help Show help for command
28
+
29
+ EXAMPLES
30
+ prismic page-type disconnect-slice homepage CallToAction
31
+ prismic page-type disconnect-slice homepage CallToAction --slice-zone slices
32
+ prismic page-type disconnect-slice article HeroSection -z body
33
+ `.trim();
34
+
35
+ const CustomTypeSchema = v.object({
36
+ id: v.string(),
37
+ label: v.string(),
38
+ repeatable: v.boolean(),
39
+ status: v.boolean(),
40
+ format: v.string(),
41
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
42
+ });
43
+
44
+ export async function pageTypeDisconnectSlice(): Promise<void> {
45
+ const {
46
+ values: { help, "slice-zone": sliceZoneId, types, "no-types": noTypes },
47
+ positionals: [typeId, sliceId],
48
+ } = parseArgs({
49
+ args: process.argv.slice(4), // skip: node, script, "page-type", "disconnect-slice"
50
+ options: {
51
+ "slice-zone": { type: "string", short: "z" },
52
+ types: { type: "string" },
53
+ "no-types": { type: "boolean" },
54
+ help: { type: "boolean", short: "h" },
55
+ },
56
+ allowPositionals: true,
57
+ });
58
+
59
+ if (help) {
60
+ console.info(HELP);
61
+ return;
62
+ }
63
+
64
+ if (!typeId) {
65
+ console.error("Missing required argument: type-id\n");
66
+ console.error("Usage: prismic page-type disconnect-slice <type-id> <slice-id>");
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+
71
+ if (!sliceId) {
72
+ console.error("Missing required argument: slice-id\n");
73
+ console.error("Usage: prismic page-type disconnect-slice <type-id> <slice-id>");
74
+ process.exitCode = 1;
75
+ return;
76
+ }
77
+
78
+ // Find the page type file
79
+ const projectRoot = await findUpward("package.json");
80
+ if (!projectRoot) {
81
+ console.error("Could not find project root (no package.json found)");
82
+ process.exitCode = 1;
83
+ return;
84
+ }
85
+
86
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
87
+
88
+ // Read and parse the model
89
+ let model: CustomType;
90
+ try {
91
+ const contents = await readFile(modelPath, "utf8");
92
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
93
+ if (!result.success) {
94
+ console.error(`Invalid page type model: ${modelPath.href}`);
95
+ process.exitCode = 1;
96
+ return;
97
+ }
98
+ model = result.output as CustomType;
99
+ } catch (error) {
100
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
101
+ console.error(`Page type not found: ${typeId}\n`);
102
+ console.error(`Create it first with: prismic page-type create ${typeId}`);
103
+ process.exitCode = 1;
104
+ return;
105
+ }
106
+ if (error instanceof Error) {
107
+ console.error(`Failed to read page type: ${error.message}`);
108
+ } else {
109
+ console.error("Failed to read page type");
110
+ }
111
+ process.exitCode = 1;
112
+ return;
113
+ }
114
+
115
+ const targetSliceZoneId = sliceZoneId ?? "slices";
116
+
117
+ // Find existing slice zone
118
+ let sliceZone: DynamicSlices | undefined;
119
+ let sliceZoneFieldId: string | undefined;
120
+
121
+ // Search all tabs for a Slices field matching the target ID
122
+ for (const [, tabFields] of Object.entries(model.json)) {
123
+ for (const [fieldId, field] of Object.entries(tabFields)) {
124
+ if ((field as { type?: string }).type === "Slices" && fieldId === targetSliceZoneId) {
125
+ sliceZone = field as DynamicSlices;
126
+ sliceZoneFieldId = fieldId;
127
+ break;
128
+ }
129
+ }
130
+ if (sliceZone) break;
131
+ }
132
+
133
+ // Slice zone must exist for disconnect
134
+ if (!sliceZone) {
135
+ console.error(`Slice zone "${targetSliceZoneId}" not found in page type "${typeId}"`);
136
+ process.exitCode = 1;
137
+ return;
138
+ }
139
+
140
+ // Check if slice is connected
141
+ if (!sliceZone.config?.choices || !(sliceId in sliceZone.config.choices)) {
142
+ console.error(
143
+ `Slice "${sliceId}" is not connected to slice zone "${sliceZoneFieldId}" in ${typeId}`,
144
+ );
145
+ process.exitCode = 1;
146
+ return;
147
+ }
148
+
149
+ // Remove the slice reference
150
+ delete sliceZone.config.choices[sliceId];
151
+
152
+ // Write updated model
153
+ try {
154
+ await writeFile(modelPath, stringify(model));
155
+ } catch (error) {
156
+ if (error instanceof Error) {
157
+ console.error(`Failed to update page type: ${error.message}`);
158
+ } else {
159
+ console.error("Failed to update page type");
160
+ }
161
+ process.exitCode = 1;
162
+ return;
163
+ }
164
+
165
+ console.info(
166
+ `Disconnected slice "${sliceId}" from slice zone "${sliceZoneFieldId}" in ${typeId}`,
167
+ );
168
+
169
+ if (!noTypes) {
170
+ try {
171
+ await buildTypes({ output: types });
172
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
173
+ } catch (error) {
174
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
175
+ }
176
+ }
177
+ }
@@ -0,0 +1,109 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import { parseArgs } from "node:util";
3
+ import * as v from "valibot";
4
+
5
+ import { findUpward } from "./lib/file";
6
+
7
+ const HELP = `
8
+ List all page types in a Prismic project.
9
+
10
+ USAGE
11
+ prismic page-type list [flags]
12
+
13
+ FLAGS
14
+ --json Output as JSON
15
+ -h, --help Show help for command
16
+
17
+ EXAMPLES
18
+ prismic page-type list
19
+ prismic page-type list --json
20
+ `.trim();
21
+
22
+ const CustomTypeSchema = v.object({
23
+ id: v.string(),
24
+ label: v.string(),
25
+ repeatable: v.boolean(),
26
+ status: v.boolean(),
27
+ format: v.optional(v.string()),
28
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
29
+ });
30
+
31
+ export async function pageTypeList(): Promise<void> {
32
+ const {
33
+ values: { help, json },
34
+ } = parseArgs({
35
+ args: process.argv.slice(4), // skip: node, script, "page-type", "list"
36
+ options: {
37
+ json: { type: "boolean" },
38
+ help: { type: "boolean", short: "h" },
39
+ },
40
+ allowPositionals: true,
41
+ });
42
+
43
+ if (help) {
44
+ console.info(HELP);
45
+ return;
46
+ }
47
+
48
+ const projectRoot = await findUpward("package.json");
49
+ if (!projectRoot) {
50
+ console.error("Could not find project root (no package.json found)");
51
+ process.exitCode = 1;
52
+ return;
53
+ }
54
+
55
+ const customTypesDirectory = new URL("customtypes/", projectRoot);
56
+
57
+ let entries: string[];
58
+ try {
59
+ entries = (await readdir(customTypesDirectory, {
60
+ withFileTypes: false,
61
+ })) as unknown as string[];
62
+ } catch {
63
+ if (json) {
64
+ console.info(JSON.stringify([]));
65
+ } else {
66
+ console.info("No page types found.");
67
+ }
68
+ return;
69
+ }
70
+
71
+ const pageTypes: { id: string; label: string; repeatable: boolean }[] = [];
72
+
73
+ for (const entry of entries) {
74
+ const modelPath = new URL(`${entry}/index.json`, customTypesDirectory);
75
+ try {
76
+ const contents = await readFile(modelPath, "utf8");
77
+ const parsed = JSON.parse(contents);
78
+ const result = v.safeParse(CustomTypeSchema, parsed);
79
+ if (result.success && result.output.format === "page") {
80
+ pageTypes.push({
81
+ id: result.output.id,
82
+ label: result.output.label,
83
+ repeatable: result.output.repeatable,
84
+ });
85
+ }
86
+ } catch {
87
+ // Skip directories without valid index.json
88
+ }
89
+ }
90
+
91
+ if (pageTypes.length === 0) {
92
+ if (json) {
93
+ console.info(JSON.stringify([]));
94
+ } else {
95
+ console.info("No page types found.");
96
+ }
97
+ return;
98
+ }
99
+
100
+ if (json) {
101
+ console.info(JSON.stringify(pageTypes, null, 2));
102
+ } else {
103
+ console.info("ID\tLABEL\tTYPE");
104
+ for (const pageType of pageTypes) {
105
+ const typeLabel = pageType.repeatable ? "repeatable" : "singleton";
106
+ console.info(`${pageType.id}\t${pageType.label}\t${typeLabel}`);
107
+ }
108
+ }
109
+ }
@@ -0,0 +1,177 @@
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
+ Remove a field from a page type.
13
+
14
+ USAGE
15
+ prismic page-type remove-field <type-id> <field-id> [flags]
16
+
17
+ ARGUMENTS
18
+ type-id Page type identifier (required)
19
+ field-id Field identifier (required)
20
+
21
+ Types are generated by default after changes. Use --no-types to skip.
22
+
23
+ FLAGS
24
+ --tab string Specific tab (searches all tabs if not specified)
25
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
26
+ --no-types Skip type generation
27
+ -h, --help Show help for command
28
+
29
+ EXAMPLES
30
+ prismic page-type remove-field homepage title
31
+ prismic page-type remove-field homepage meta_title --tab "SEO & Metadata"
32
+ `.trim();
33
+
34
+ const CustomTypeSchema = v.object({
35
+ id: v.string(),
36
+ label: v.string(),
37
+ repeatable: v.boolean(),
38
+ status: v.boolean(),
39
+ format: v.optional(v.string()),
40
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
41
+ });
42
+
43
+ export async function pageTypeRemoveField(): Promise<void> {
44
+ const {
45
+ values: { help, tab, types, "no-types": noTypes },
46
+ positionals: [typeId, fieldId],
47
+ } = parseArgs({
48
+ args: process.argv.slice(4), // skip: node, script, "page-type", "remove-field"
49
+ options: {
50
+ tab: { type: "string" },
51
+ types: { type: "string" },
52
+ "no-types": { type: "boolean" },
53
+ help: { type: "boolean", short: "h" },
54
+ },
55
+ allowPositionals: true,
56
+ });
57
+
58
+ if (help) {
59
+ console.info(HELP);
60
+ return;
61
+ }
62
+
63
+ if (!typeId) {
64
+ console.error("Missing required argument: type-id\n");
65
+ console.error("Usage: prismic page-type remove-field <type-id> <field-id>");
66
+ process.exitCode = 1;
67
+ return;
68
+ }
69
+
70
+ if (!fieldId) {
71
+ console.error("Missing required argument: field-id\n");
72
+ console.error("Usage: prismic page-type remove-field <type-id> <field-id>");
73
+ process.exitCode = 1;
74
+ return;
75
+ }
76
+
77
+ const projectRoot = await findUpward("package.json");
78
+ if (!projectRoot) {
79
+ console.error("Could not find project root (no package.json found)");
80
+ process.exitCode = 1;
81
+ return;
82
+ }
83
+
84
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
85
+
86
+ // Read and parse the model
87
+ let model: CustomType;
88
+ try {
89
+ const contents = await readFile(modelPath, "utf8");
90
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
91
+ if (!result.success) {
92
+ console.error(`Invalid page type model: ${modelPath.href}`);
93
+ process.exitCode = 1;
94
+ return;
95
+ }
96
+ model = result.output as CustomType;
97
+ } catch (error) {
98
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
99
+ console.error(`Page type not found: ${typeId}\n`);
100
+ console.error(`Create it first with: prismic page-type create ${typeId}`);
101
+ process.exitCode = 1;
102
+ return;
103
+ }
104
+ if (error instanceof Error) {
105
+ console.error(`Failed to read page type: ${error.message}`);
106
+ } else {
107
+ console.error("Failed to read page type");
108
+ }
109
+ process.exitCode = 1;
110
+ return;
111
+ }
112
+
113
+ // Check if this is actually a page type
114
+ if (model.format !== "page") {
115
+ console.error(`"${typeId}" is not a page type (format: ${model.format ?? "custom"})`);
116
+ process.exitCode = 1;
117
+ return;
118
+ }
119
+
120
+ // Find and remove the field
121
+ let foundTab: string | undefined;
122
+
123
+ if (tab) {
124
+ // Look in specific tab
125
+ if (!model.json[tab]) {
126
+ console.error(`Tab "${tab}" not found in page type "${typeId}"`);
127
+ console.error(`Available tabs: ${Object.keys(model.json).join(", ")}`);
128
+ process.exitCode = 1;
129
+ return;
130
+ }
131
+ if (!(fieldId in model.json[tab])) {
132
+ console.error(`Field "${fieldId}" not found in tab "${tab}"`);
133
+ process.exitCode = 1;
134
+ return;
135
+ }
136
+ delete model.json[tab][fieldId];
137
+ foundTab = tab;
138
+ } else {
139
+ // Search all tabs
140
+ for (const [tabName, tabFields] of Object.entries(model.json)) {
141
+ if (fieldId in tabFields) {
142
+ delete tabFields[fieldId];
143
+ foundTab = tabName;
144
+ break;
145
+ }
146
+ }
147
+ if (!foundTab) {
148
+ console.error(`Field "${fieldId}" not found in any tab of page type "${typeId}"`);
149
+ process.exitCode = 1;
150
+ return;
151
+ }
152
+ }
153
+
154
+ // Write updated model
155
+ try {
156
+ await writeFile(modelPath, stringify(model));
157
+ } catch (error) {
158
+ if (error instanceof Error) {
159
+ console.error(`Failed to update page type: ${error.message}`);
160
+ } else {
161
+ console.error("Failed to update page type");
162
+ }
163
+ process.exitCode = 1;
164
+ return;
165
+ }
166
+
167
+ console.info(`Removed field "${fieldId}" from tab "${foundTab}" in page type "${typeId}"`);
168
+
169
+ if (!noTypes) {
170
+ try {
171
+ await buildTypes({ output: types });
172
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
173
+ } catch (error) {
174
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
175
+ }
176
+ }
177
+ }