@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,235 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFile, writeFile } from "node:fs/promises";
3
+ import { extname } from "node:path";
4
+ import { parseArgs } from "node:util";
5
+ import * as v from "valibot";
6
+
7
+ import { isAuthenticated } from "./lib/auth";
8
+ import { safeGetRepositoryFromConfig } from "./lib/config";
9
+ import { stringify } from "./lib/json";
10
+ import { request } from "./lib/request";
11
+ import { findSliceModel } from "./lib/slice";
12
+
13
+ const HELP = `
14
+ Set a screenshot for a slice variation.
15
+
16
+ USAGE
17
+ prismic slice set-screenshot <slice-id> <image-path> [flags]
18
+
19
+ ARGUMENTS
20
+ slice-id Slice identifier (required)
21
+ image-path Path to the image file (required)
22
+
23
+ FLAGS
24
+ -v, --variation string Variation ID (default: "default")
25
+ -r, --repo string Repository name (uses config if not provided)
26
+ -h, --help Show help for command
27
+
28
+ EXAMPLES
29
+ prismic slice set-screenshot MySlice ./screenshot.png
30
+ prismic slice set-screenshot MySlice ./screenshot.png --variation dark
31
+ prismic slice set-screenshot MySlice ./screenshot.png --repo my-repo
32
+ `.trim();
33
+
34
+ const ACLCreateResponseSchema = v.object({
35
+ uploadEndpoint: v.string(),
36
+ requiredFormDataFields: v.record(v.string(), v.string()),
37
+ imgixEndpoint: v.string(),
38
+ });
39
+
40
+ export type UploadScreenshotArgs = {
41
+ data: Buffer;
42
+ repo: string;
43
+ sliceId: string;
44
+ variationId: string;
45
+ filename: string;
46
+ };
47
+
48
+ export async function uploadScreenshot(args: UploadScreenshotArgs): Promise<string> {
49
+ const { data, repo, sliceId, variationId, filename } = args;
50
+
51
+ // Get upload credentials from ACL provider
52
+ const aclResponse = await request("https://acl-provider.prismic.io/create", {
53
+ method: "POST",
54
+ body: {},
55
+ schema: ACLCreateResponseSchema,
56
+ });
57
+
58
+ if (!aclResponse.ok) {
59
+ throw new Error("Failed to get upload credentials from Prismic");
60
+ }
61
+
62
+ const { uploadEndpoint, requiredFormDataFields, imgixEndpoint } = aclResponse.value;
63
+
64
+ // Generate content digest for unique filename
65
+ const digest = createHash("md5").update(data).digest("hex");
66
+ const ext = extname(filename).toLowerCase().slice(1) || "png";
67
+
68
+ // Build the S3 key path
69
+ const key = `${repo}/shared-slices/${sliceId}/${variationId}/${digest}.${ext}`;
70
+
71
+ // Create FormData for S3 upload
72
+ const formData = new FormData();
73
+ for (const [field, value] of Object.entries(requiredFormDataFields)) {
74
+ formData.append(field, value);
75
+ }
76
+ formData.append("key", key);
77
+ formData.append("Content-Type", getMimeType(ext));
78
+ formData.append("file", new Blob([new Uint8Array(data)], { type: getMimeType(ext) }), filename);
79
+
80
+ // Upload to S3
81
+ const uploadResponse = await fetch(uploadEndpoint, {
82
+ method: "POST",
83
+ body: formData,
84
+ });
85
+
86
+ if (!uploadResponse.ok) {
87
+ const text = await uploadResponse.text();
88
+ throw new Error(`Failed to upload screenshot: ${text}`);
89
+ }
90
+
91
+ // Construct Imgix URL
92
+ const imgixUrl = `${imgixEndpoint}/${key}?auto=compress,format`;
93
+
94
+ return imgixUrl;
95
+ }
96
+
97
+ function getMimeType(ext: string): string {
98
+ switch (ext) {
99
+ case "png":
100
+ return "image/png";
101
+ case "jpg":
102
+ case "jpeg":
103
+ return "image/jpeg";
104
+ case "gif":
105
+ return "image/gif";
106
+ case "webp":
107
+ return "image/webp";
108
+ default:
109
+ return "image/png";
110
+ }
111
+ }
112
+
113
+ export async function sliceSetScreenshot(): Promise<void> {
114
+ const {
115
+ values: { help, variation, repo: repoFlag },
116
+ positionals: [sliceId, imagePath],
117
+ } = parseArgs({
118
+ args: process.argv.slice(4), // skip: node, script, "slice", "set-screenshot"
119
+ options: {
120
+ variation: { type: "string", short: "v", default: "default" },
121
+ repo: { type: "string", short: "r" },
122
+ help: { type: "boolean", short: "h" },
123
+ },
124
+ allowPositionals: true,
125
+ });
126
+
127
+ if (help) {
128
+ console.info(HELP);
129
+ return;
130
+ }
131
+
132
+ if (!sliceId) {
133
+ console.error("Missing required argument: slice-id\n");
134
+ console.error("Usage: prismic slice set-screenshot <slice-id> <image-path>");
135
+ process.exitCode = 1;
136
+ return;
137
+ }
138
+
139
+ if (!imagePath) {
140
+ console.error("Missing required argument: image-path\n");
141
+ console.error("Usage: prismic slice set-screenshot <slice-id> <image-path>");
142
+ process.exitCode = 1;
143
+ return;
144
+ }
145
+
146
+ // Check authentication
147
+ const authenticated = await isAuthenticated();
148
+ if (!authenticated) {
149
+ console.error("You must be logged in to set a screenshot.");
150
+ console.error("Run `prismic login` to authenticate.");
151
+ process.exitCode = 1;
152
+ return;
153
+ }
154
+
155
+ // Resolve repository
156
+ const repo = repoFlag ?? (await safeGetRepositoryFromConfig());
157
+ if (!repo) {
158
+ console.error("Could not determine repository.");
159
+ console.error("Use --repo flag or run from a directory with prismic.config.json");
160
+ process.exitCode = 1;
161
+ return;
162
+ }
163
+
164
+ // Find the slice model
165
+ const result = await findSliceModel(sliceId);
166
+ if (!result.ok) {
167
+ console.error(result.error);
168
+ process.exitCode = 1;
169
+ return;
170
+ }
171
+
172
+ const { model, modelPath } = result;
173
+
174
+ // Find the variation
175
+ const variationIndex = model.variations.findIndex((v) => v.id === variation);
176
+ if (variationIndex === -1) {
177
+ console.error(`Variation "${variation}" not found in slice "${sliceId}"`);
178
+ console.error(`Available variations: ${model.variations.map((v) => v.id).join(", ")}`);
179
+ process.exitCode = 1;
180
+ return;
181
+ }
182
+
183
+ // Read the image file
184
+ let imageData: Buffer;
185
+ try {
186
+ imageData = await readFile(imagePath);
187
+ } catch (error) {
188
+ if (error instanceof Error) {
189
+ console.error(`Failed to read image file: ${error.message}`);
190
+ } else {
191
+ console.error("Failed to read image file");
192
+ }
193
+ process.exitCode = 1;
194
+ return;
195
+ }
196
+
197
+ // Upload the screenshot
198
+ let imageUrl: string;
199
+ try {
200
+ imageUrl = await uploadScreenshot({
201
+ data: imageData,
202
+ repo,
203
+ sliceId,
204
+ variationId: variation ?? "default",
205
+ filename: imagePath,
206
+ });
207
+ } catch (error) {
208
+ if (error instanceof Error) {
209
+ console.error(`Failed to upload screenshot: ${error.message}`);
210
+ } else {
211
+ console.error("Failed to upload screenshot");
212
+ }
213
+ process.exitCode = 1;
214
+ return;
215
+ }
216
+
217
+ // Update the model
218
+ model.variations[variationIndex].imageUrl = imageUrl;
219
+
220
+ // Write updated model
221
+ try {
222
+ await writeFile(modelPath, stringify(model));
223
+ } catch (error) {
224
+ if (error instanceof Error) {
225
+ console.error(`Failed to update slice model: ${error.message}`);
226
+ } else {
227
+ console.error("Failed to update slice model");
228
+ }
229
+ process.exitCode = 1;
230
+ return;
231
+ }
232
+
233
+ console.info(`Screenshot set for slice "${sliceId}" variation "${variation}"`);
234
+ console.info(`URL: ${imageUrl}`);
235
+ }
@@ -0,0 +1,80 @@
1
+ import { parseArgs } from "node:util";
2
+
3
+ import { findSliceModel } from "./lib/slice";
4
+
5
+ const HELP = `
6
+ View details of a specific slice.
7
+
8
+ USAGE
9
+ prismic slice view <slice-id> [flags]
10
+
11
+ ARGUMENTS
12
+ slice-id Slice identifier (required)
13
+
14
+ FLAGS
15
+ --json Output as JSON
16
+ -h, --help Show help for command
17
+
18
+ EXAMPLES
19
+ prismic slice view MySlice
20
+ prismic slice view MySlice --json
21
+ `.trim();
22
+
23
+ export async function sliceView(): Promise<void> {
24
+ const {
25
+ values: { help, json },
26
+ positionals: [sliceId],
27
+ } = parseArgs({
28
+ args: process.argv.slice(4), // skip: node, script, "slice", "view"
29
+ options: {
30
+ json: { type: "boolean" },
31
+ help: { type: "boolean", short: "h" },
32
+ },
33
+ allowPositionals: true,
34
+ });
35
+
36
+ if (help) {
37
+ console.info(HELP);
38
+ return;
39
+ }
40
+
41
+ if (!sliceId) {
42
+ console.error("Missing required argument: slice-id\n");
43
+ console.error("Usage: prismic slice view <slice-id>");
44
+ process.exitCode = 1;
45
+ return;
46
+ }
47
+
48
+ const result = await findSliceModel(sliceId);
49
+ if (!result.ok) {
50
+ console.error(result.error);
51
+ process.exitCode = 1;
52
+ return;
53
+ }
54
+
55
+ const { model } = result;
56
+
57
+ if (json) {
58
+ console.info(JSON.stringify(model, null, 2));
59
+ return;
60
+ }
61
+
62
+ console.info(`ID: ${model.id}`);
63
+ console.info(`Name: ${model.name}`);
64
+ if (model.description) {
65
+ console.info(`Description: ${model.description}`);
66
+ }
67
+ console.info(`Variations: ${model.variations.length}`);
68
+
69
+ console.info("\nVariations:");
70
+ for (const variation of model.variations) {
71
+ const primaryFields = Object.keys(variation.primary ?? {}).length;
72
+ const itemsFields = Object.keys(variation.items ?? {}).length;
73
+ console.info(
74
+ ` - ${variation.id} (${variation.name}): ${primaryFields} primary fields, ${itemsFields} items fields`,
75
+ );
76
+ if (variation.imageUrl) {
77
+ console.info(` Screenshot: ${variation.imageUrl}`);
78
+ }
79
+ }
80
+ }
package/src/slice.ts ADDED
@@ -0,0 +1,95 @@
1
+ import { parseArgs } from "node:util";
2
+
3
+ import { sliceAddField } from "./slice-add-field";
4
+ import { sliceAddVariation } from "./slice-add-variation";
5
+ import { sliceCreate } from "./slice-create";
6
+ import { sliceList } from "./slice-list";
7
+ import { sliceListVariations } from "./slice-list-variations";
8
+ import { sliceRemove } from "./slice-remove";
9
+ import { sliceRemoveField } from "./slice-remove-field";
10
+ import { sliceRemoveVariation } from "./slice-remove-variation";
11
+ import { sliceRename } from "./slice-rename";
12
+ import { sliceSetScreenshot } from "./slice-set-screenshot";
13
+ import { sliceView } from "./slice-view";
14
+
15
+ const HELP = `
16
+ Manage slices in a Prismic project.
17
+
18
+ USAGE
19
+ prismic slice <command> [flags]
20
+
21
+ COMMANDS
22
+ create Create a new slice
23
+ list List all slices
24
+ view View details of a slice
25
+ rename Rename a slice
26
+ remove Remove a slice
27
+ add-field Add a field to a slice
28
+ remove-field Remove a field from a slice
29
+ add-variation Add a variation to a slice
30
+ remove-variation Remove a variation from a slice
31
+ list-variations List all variations of a slice
32
+ set-screenshot Set a screenshot for a slice variation
33
+
34
+ FLAGS
35
+ -h, --help Show help for command
36
+
37
+ LEARN MORE
38
+ Use \`prismic slice <command> --help\` for more information about a command.
39
+ `.trim();
40
+
41
+ export async function slice(): Promise<void> {
42
+ const {
43
+ positionals: [subcommand],
44
+ } = parseArgs({
45
+ args: process.argv.slice(3), // skip: node, script, "slice"
46
+ options: {
47
+ help: { type: "boolean", short: "h" },
48
+ },
49
+ allowPositionals: true,
50
+ strict: false,
51
+ });
52
+
53
+ switch (subcommand) {
54
+ case "create":
55
+ await sliceCreate();
56
+ break;
57
+ case "list":
58
+ await sliceList();
59
+ break;
60
+ case "view":
61
+ await sliceView();
62
+ break;
63
+ case "rename":
64
+ await sliceRename();
65
+ break;
66
+ case "remove":
67
+ await sliceRemove();
68
+ break;
69
+ case "add-field":
70
+ await sliceAddField();
71
+ break;
72
+ case "remove-field":
73
+ await sliceRemoveField();
74
+ break;
75
+ case "add-variation":
76
+ await sliceAddVariation();
77
+ break;
78
+ case "remove-variation":
79
+ await sliceRemoveVariation();
80
+ break;
81
+ case "list-variations":
82
+ await sliceListVariations();
83
+ break;
84
+ case "set-screenshot":
85
+ await sliceSetScreenshot();
86
+ break;
87
+ default: {
88
+ if (subcommand) {
89
+ console.error(`Unknown slice subcommand: ${subcommand}\n`);
90
+ process.exitCode = 1;
91
+ }
92
+ console.info(HELP);
93
+ }
94
+ }
95
+ }