prismic 1.1.0 → 1.2.0

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 (48) hide show
  1. package/dist/{builders-hKD4IrLX-ClhMQQkN.mjs → builders-hKD4IrLX-BrpqCAS2.mjs} +1 -1
  2. package/dist/index.mjs +115 -101
  3. package/dist/nextjs-HiDO_p-p.mjs +318 -0
  4. package/dist/nuxt-CDrqbn0o.mjs +59 -0
  5. package/dist/string-BUjs_2AH.mjs +7 -0
  6. package/dist/{sveltekit-BMDXAfYz.mjs → sveltekit-Qx8xJZOd.mjs} +45 -35
  7. package/package.json +1 -1
  8. package/src/adapters/index.ts +177 -0
  9. package/src/{frameworks → adapters}/nextjs.templates.ts +102 -102
  10. package/src/adapters/nextjs.ts +211 -0
  11. package/src/adapters/nuxt.ts +232 -0
  12. package/src/adapters/sveltekit.ts +226 -0
  13. package/src/clients/core.ts +104 -0
  14. package/src/clients/wroom.ts +111 -0
  15. package/src/commands/init.ts +57 -69
  16. package/src/commands/login.ts +12 -29
  17. package/src/commands/logout.ts +8 -28
  18. package/src/commands/preview-add.ts +57 -0
  19. package/src/commands/preview-list.ts +54 -0
  20. package/src/commands/preview-remove.ts +51 -0
  21. package/src/commands/preview-set-simulator.ts +60 -0
  22. package/src/commands/preview.ts +28 -0
  23. package/src/commands/sync.ts +49 -87
  24. package/src/commands/webhook-create.ts +89 -0
  25. package/src/commands/webhook-disable.ts +60 -0
  26. package/src/commands/webhook-enable.ts +60 -0
  27. package/src/commands/webhook-list.ts +43 -0
  28. package/src/commands/webhook-remove.ts +52 -0
  29. package/src/commands/webhook-set-triggers.ts +93 -0
  30. package/src/commands/webhook-view.ts +65 -0
  31. package/src/commands/webhook.ts +43 -0
  32. package/src/commands/whoami.ts +7 -28
  33. package/src/config.ts +2 -11
  34. package/src/index.ts +122 -105
  35. package/src/lib/command.ts +188 -0
  36. package/src/lib/file.ts +13 -1
  37. package/src/lib/packageJson.ts +70 -1
  38. package/src/lib/segment.ts +26 -30
  39. package/src/project.ts +54 -0
  40. package/dist/frameworks-DtGBrEuY.mjs +0 -17
  41. package/dist/nextjs-2qjzSaQI.mjs +0 -312
  42. package/dist/nuxt-DKsgbqpV.mjs +0 -59
  43. package/src/frameworks/index.ts +0 -398
  44. package/src/frameworks/nextjs.ts +0 -211
  45. package/src/frameworks/nuxt.ts +0 -252
  46. package/src/frameworks/sveltekit.ts +0 -234
  47. /package/src/{frameworks → adapters}/nuxt.templates.ts +0 -0
  48. /package/src/{frameworks → adapters}/sveltekit.templates.ts +0 -0
@@ -0,0 +1,60 @@
1
+ import { getHost, getToken } from "../auth";
2
+ import { setSimulatorUrl } from "../clients/core";
3
+ import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4
+ import { UnknownRequestError } from "../lib/request";
5
+ import { getRepositoryName } from "../project";
6
+
7
+ const config = {
8
+ name: "prismic preview set-simulator",
9
+ description: `
10
+ Set the slice simulator URL for a Prismic repository.
11
+
12
+ If the URL pathname does not end with /slice-simulator, it is appended
13
+ automatically.
14
+
15
+ By default, this command reads the repository from prismic.config.json at the
16
+ project root.
17
+ `,
18
+ positionals: {
19
+ url: { description: "Simulator URL (e.g. https://example.com/slice-simulator)" },
20
+ },
21
+ options: {
22
+ repo: { type: "string", short: "r", description: "Repository domain" },
23
+ },
24
+ } satisfies CommandConfig;
25
+
26
+ export default createCommand(config, async ({ positionals, values }) => {
27
+ const [urlArg] = positionals;
28
+ const { repo = await getRepositoryName() } = values;
29
+
30
+ if (!urlArg) {
31
+ throw new CommandError("Missing required argument: <url>");
32
+ }
33
+
34
+ let parsed: URL;
35
+ try {
36
+ parsed = new URL(urlArg);
37
+ } catch {
38
+ throw new CommandError(`Invalid URL: ${urlArg}`);
39
+ }
40
+
41
+ if (!parsed.pathname.endsWith("/slice-simulator")) {
42
+ parsed.pathname = parsed.pathname.replace(/\/+$/, "") + "/slice-simulator";
43
+ }
44
+ const simulatorUrl = parsed.toString();
45
+
46
+ const token = await getToken();
47
+ const host = await getHost();
48
+
49
+ try {
50
+ await setSimulatorUrl(simulatorUrl, { repo, token, host });
51
+ } catch (error) {
52
+ if (error instanceof UnknownRequestError) {
53
+ const message = await error.text();
54
+ throw new CommandError(`Failed to set simulator URL: ${message}`);
55
+ }
56
+ throw error;
57
+ }
58
+
59
+ console.info(`Simulator URL set: ${simulatorUrl}`);
60
+ });
@@ -0,0 +1,28 @@
1
+ import { createCommandRouter } from "../lib/command";
2
+ import previewAdd from "./preview-add";
3
+ import previewList from "./preview-list";
4
+ import previewRemove from "./preview-remove";
5
+ import previewSetSimulator from "./preview-set-simulator";
6
+
7
+ export default createCommandRouter({
8
+ name: "prismic preview",
9
+ description: "Manage preview configurations in a Prismic repository.",
10
+ commands: {
11
+ add: {
12
+ handler: previewAdd,
13
+ description: "Add a preview configuration",
14
+ },
15
+ list: {
16
+ handler: previewList,
17
+ description: "List preview configurations",
18
+ },
19
+ remove: {
20
+ handler: previewRemove,
21
+ description: "Remove a preview configuration",
22
+ },
23
+ "set-simulator": {
24
+ handler: previewSetSimulator,
25
+ description: "Set the slice simulator URL",
26
+ },
27
+ },
28
+ });
@@ -1,103 +1,65 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { setTimeout } from "node:timers/promises";
3
- import { parseArgs } from "node:util";
4
3
 
4
+ import { getAdapter, type Adapter } from "../adapters";
5
5
  import { getHost, getToken } from "../auth";
6
6
  import { getCustomTypes, getSlices } from "../clients/custom-types";
7
- import { safeGetRepositoryFromConfig } from "../config";
8
- import { type FrameworkAdapter, NoSupportedFrameworkError, requireFramework } from "../frameworks";
9
7
  import { generateAndWriteTypes } from "../lib/codegen";
10
- import { segmentSetRepository, segmentTrackEnd, segmentTrackStart } from "../lib/segment";
11
- import { sentrySetContext, sentrySetTag } from "../lib/sentry";
8
+ import { createCommand, type CommandConfig } from "../lib/command";
9
+ import { segmentTrackEnd, segmentTrackStart } from "../lib/segment";
12
10
  import { dedent } from "../lib/string";
13
-
14
- const HELP = `
15
- Sync slices, page types, and custom types from Prismic to local files.
16
-
17
- Remote models are the source of truth. Local files are created, updated,
18
- or deleted to match.
19
-
20
- USAGE
21
- prismic sync [flags]
22
-
23
- FLAGS
24
- -r, --repo string Repository domain
25
- -w, --watch Watch for changes and sync continuously
26
- -h, --help Show help for command
27
- `.trim();
11
+ import { findProjectRoot, getRepositoryName } from "../project";
28
12
 
29
13
  // 5 seconds balances responsiveness with API load
30
14
  const POLL_INTERVAL_MS = 5000;
31
15
  const MAX_BACKOFF_MS = 60000; // Cap backoff at 1 minute
32
16
  const MAX_CONSECUTIVE_ERRORS = 10;
33
17
 
34
- export async function sync(): Promise<void> {
35
- const {
36
- values: { help, repo = await safeGetRepositoryFromConfig(), watch },
37
- } = parseArgs({
38
- args: process.argv.slice(3), // skip: node, script, "sync"
39
- options: {
40
- repo: { type: "string", short: "r" },
41
- watch: { type: "boolean", short: "w" },
42
- help: { type: "boolean", short: "h" },
43
- },
44
- allowPositionals: false,
45
- });
18
+ const config = {
19
+ name: "prismic sync",
20
+ description: `
21
+ Sync slices, page types, and custom types from Prismic to local files.
46
22
 
47
- if (help) {
48
- console.info(HELP);
49
- return;
50
- }
23
+ Remote models are the source of truth. Local files are created, updated,
24
+ or deleted to match.
25
+ `,
26
+ options: {
27
+ repo: { type: "string", short: "r", description: "Repository domain" },
28
+ watch: { type: "boolean", short: "w", description: "Watch for changes and sync continuously" },
29
+ },
30
+ } satisfies CommandConfig;
51
31
 
52
- if (!repo) {
53
- console.error("Missing prismic.config.json or --repo option");
54
- process.exitCode = 1;
55
- return;
56
- }
32
+ export default createCommand(config, async ({ values }) => {
33
+ const { repo = await getRepositoryName(), watch } = values;
57
34
 
58
- // Override analytics repository context with the resolved repo
59
- segmentSetRepository(repo);
60
- sentrySetTag("repository", repo);
61
- sentrySetContext("Repository Data", { name: repo });
62
-
63
- let framework: FrameworkAdapter;
64
- try {
65
- framework = await requireFramework();
66
- } catch (error) {
67
- if (error instanceof NoSupportedFrameworkError) {
68
- console.error(error.message);
69
- process.exitCode = 1;
70
- return;
71
- }
72
- throw error;
73
- }
35
+ const adapter = await getAdapter();
74
36
 
75
37
  console.info(`Syncing from repository: ${repo}`);
76
38
 
77
- segmentTrackStart("sync", { repository: repo });
39
+ segmentTrackStart("sync", { watch });
78
40
 
79
41
  if (watch) {
80
- await watchForChanges(repo, framework);
42
+ await watchForChanges(repo, adapter);
81
43
  } else {
82
- await syncSlices(repo, framework);
83
- await syncCustomTypes(repo, framework);
84
- await regenerateTypes(framework);
85
- segmentTrackEnd("sync", true, undefined, { watch: false });
44
+ await syncSlices(repo, adapter);
45
+ await syncCustomTypes(repo, adapter);
46
+ await regenerateTypes(adapter);
47
+ segmentTrackEnd("sync", { watch });
86
48
 
87
49
  console.info("Sync complete");
88
50
  }
89
- }
51
+ });
90
52
 
91
- async function watchForChanges(repo: string, framework: FrameworkAdapter) {
53
+ async function watchForChanges(repo: string, adapter: Adapter) {
92
54
  const token = await getToken();
93
55
  const host = await getHost();
94
56
 
95
57
  const initialRemoteSlices = await getSlices({ repo, token, host });
96
58
  const initialRemoteCustomTypes = await getCustomTypes({ repo, token, host });
97
59
 
98
- await syncSlices(repo, framework);
99
- await syncCustomTypes(repo, framework);
100
- await regenerateTypes(framework);
60
+ await syncSlices(repo, adapter);
61
+ await syncCustomTypes(repo, adapter);
62
+ await regenerateTypes(adapter);
101
63
 
102
64
  console.info(dedent`
103
65
  Initial sync completed!
@@ -136,17 +98,17 @@ async function watchForChanges(repo: string, framework: FrameworkAdapter) {
136
98
  const changed = [];
137
99
 
138
100
  if (slicesChanged) {
139
- await syncSlices(repo, framework);
101
+ await syncSlices(repo, adapter);
140
102
  lastRemoteSlicesHash = remoteSlicesHash;
141
103
  changed.push("slices");
142
104
  }
143
105
  if (customTypesChanged) {
144
- await syncCustomTypes(repo, framework);
106
+ await syncCustomTypes(repo, adapter);
145
107
  lastRemoteCustomTypesHash = remoteCustomTypesHash;
146
108
  changed.push("custom types");
147
109
  }
148
110
 
149
- await regenerateTypes(framework);
111
+ await regenerateTypes(adapter);
150
112
 
151
113
  const timestamp = new Date().toLocaleTimeString();
152
114
  console.info(`[${timestamp}] Changes detected in ${changed.join(" and ")}`);
@@ -173,18 +135,18 @@ async function watchForChanges(repo: string, framework: FrameworkAdapter) {
173
135
  }
174
136
  }
175
137
 
176
- export async function syncSlices(repo: string, framework: FrameworkAdapter): Promise<void> {
138
+ export async function syncSlices(repo: string, adapter: Adapter): Promise<void> {
177
139
  const token = await getToken();
178
140
  const host = await getHost();
179
141
 
180
142
  const remoteSlices = await getSlices({ repo, token, host });
181
- const localSlices = await framework.getSlices();
143
+ const localSlices = await adapter.getSlices();
182
144
 
183
145
  // Handle slices update
184
146
  for (const remoteSlice of remoteSlices) {
185
147
  const localSlice = localSlices.find((slice) => slice.model.id === remoteSlice.id);
186
148
  if (localSlice) {
187
- await framework.updateSlice(remoteSlice);
149
+ await adapter.updateSlice(remoteSlice);
188
150
  }
189
151
  }
190
152
 
@@ -192,26 +154,26 @@ export async function syncSlices(repo: string, framework: FrameworkAdapter): Pro
192
154
  for (const localSlice of localSlices) {
193
155
  const existsRemotely = remoteSlices.some((slice) => slice.id === localSlice.model.id);
194
156
  if (!existsRemotely) {
195
- await framework.deleteSlice(localSlice.model.id);
157
+ await adapter.deleteSlice(localSlice.model.id);
196
158
  }
197
159
  }
198
160
 
199
161
  // Handle slices creation
200
- const defaultLibrary = await framework.getDefaultSliceLibrary();
162
+ const defaultLibrary = await adapter.getDefaultSliceLibrary();
201
163
  for (const remoteSlice of remoteSlices) {
202
164
  const existsLocally = localSlices.some((slice) => slice.model.id === remoteSlice.id);
203
165
  if (!existsLocally) {
204
- await framework.createSlice(remoteSlice, defaultLibrary);
166
+ await adapter.createSlice(remoteSlice, defaultLibrary);
205
167
  }
206
168
  }
207
169
  }
208
170
 
209
- export async function syncCustomTypes(repo: string, framework: FrameworkAdapter): Promise<void> {
171
+ export async function syncCustomTypes(repo: string, adapter: Adapter): Promise<void> {
210
172
  const token = await getToken();
211
173
  const host = await getHost();
212
174
 
213
175
  const remoteCustomTypes = await getCustomTypes({ repo, token, host });
214
- const localCustomTypes = await framework.getCustomTypes();
176
+ const localCustomTypes = await adapter.getCustomTypes();
215
177
 
216
178
  // Handle custom types update
217
179
  for (const remoteCustomType of remoteCustomTypes) {
@@ -219,7 +181,7 @@ export async function syncCustomTypes(repo: string, framework: FrameworkAdapter)
219
181
  (customType) => customType.model.id === remoteCustomType.id,
220
182
  );
221
183
  if (localCustomType) {
222
- await framework.updateCustomType(remoteCustomType);
184
+ await adapter.updateCustomType(remoteCustomType);
223
185
  }
224
186
  }
225
187
 
@@ -229,7 +191,7 @@ export async function syncCustomTypes(repo: string, framework: FrameworkAdapter)
229
191
  (customType) => customType.id === localCustomType.model.id,
230
192
  );
231
193
  if (!existsRemotely) {
232
- await framework.deleteCustomType(localCustomType.model.id);
194
+ await adapter.deleteCustomType(localCustomType.model.id);
233
195
  }
234
196
  }
235
197
 
@@ -239,14 +201,14 @@ export async function syncCustomTypes(repo: string, framework: FrameworkAdapter)
239
201
  (customType) => customType.model.id === remoteCustomType.id,
240
202
  );
241
203
  if (!existsLocally) {
242
- await framework.createCustomType(remoteCustomType);
204
+ await adapter.createCustomType(remoteCustomType);
243
205
  }
244
206
  }
245
207
  }
246
208
 
247
209
  function shutdown(): void {
248
210
  console.info("Watch stopped. Goodbye!");
249
- segmentTrackEnd("sync", true, undefined, { watch: true });
211
+ segmentTrackEnd("sync", { watch: true });
250
212
  process.exit(0);
251
213
  }
252
214
 
@@ -260,10 +222,10 @@ function hash(data: unknown): string {
260
222
  return createHash("sha256").update(JSON.stringify(data)).digest("hex");
261
223
  }
262
224
 
263
- async function regenerateTypes(framework: FrameworkAdapter): Promise<void> {
264
- const slices = await framework.getSlices();
265
- const customTypes = await framework.getCustomTypes();
266
- const projectRoot = await framework.getProjectRoot();
225
+ async function regenerateTypes(adapter: Adapter): Promise<void> {
226
+ const slices = await adapter.getSlices();
227
+ const customTypes = await adapter.getCustomTypes();
228
+ const projectRoot = await findProjectRoot();
267
229
  await generateAndWriteTypes({
268
230
  customTypes: customTypes.map((customType) => customType.model),
269
231
  slices: slices.map((slice) => slice.model),
@@ -0,0 +1,89 @@
1
+ import { getHost, getToken } from "../auth";
2
+ import { createWebhook, WEBHOOK_TRIGGERS } from "../clients/wroom";
3
+ import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4
+ import { UnknownRequestError } from "../lib/request";
5
+ import { getRepositoryName } from "../project";
6
+
7
+ const config = {
8
+ name: "prismic webhook create",
9
+ description: `
10
+ Create a new webhook in a Prismic repository.
11
+
12
+ By default, this command reads the repository from prismic.config.json at the
13
+ project root.
14
+ `,
15
+ positionals: {
16
+ url: { description: "Webhook URL to receive events" },
17
+ },
18
+ options: {
19
+ name: { type: "string", short: "n", description: "Webhook name" },
20
+ secret: { type: "string", short: "s", description: "Secret for webhook signature" },
21
+ trigger: {
22
+ type: "string",
23
+ multiple: true,
24
+ short: "t",
25
+ description: "Trigger events (can be repeated)",
26
+ },
27
+ repo: { type: "string", short: "r", description: "Repository domain" },
28
+ },
29
+ sections: {
30
+ TRIGGERS: `
31
+ documentsPublished When documents are published
32
+ documentsUnpublished When documents are unpublished
33
+ releasesCreated When a release is created
34
+ releasesUpdated When a release is edited or deleted
35
+ tagsCreated When a tag is created
36
+ tagsDeleted When a tag is deleted
37
+
38
+ If no triggers specified, all are enabled.
39
+ `,
40
+ },
41
+ } satisfies CommandConfig;
42
+
43
+ export default createCommand(config, async ({ positionals, values }) => {
44
+ const [webhookUrl] = positionals;
45
+ const { repo = await getRepositoryName(), name, secret, trigger = [] } = values;
46
+
47
+ if (!webhookUrl) {
48
+ throw new CommandError("Missing required argument: <url>");
49
+ }
50
+
51
+ // Validate triggers
52
+ for (const t of trigger) {
53
+ if (!WEBHOOK_TRIGGERS.includes(t)) {
54
+ throw new CommandError(
55
+ `Invalid trigger: ${t}\nValid triggers: ${WEBHOOK_TRIGGERS.join(", ")}`,
56
+ );
57
+ }
58
+ }
59
+
60
+ const token = await getToken();
61
+ const host = await getHost();
62
+
63
+ const defaultValue = trigger.length > 0 ? false : true;
64
+
65
+ try {
66
+ await createWebhook(
67
+ {
68
+ url: webhookUrl,
69
+ name: name ?? null,
70
+ secret: secret ?? null,
71
+ documentsPublished: trigger.includes("documentsPublished") || defaultValue,
72
+ documentsUnpublished: trigger.includes("documentsUnpublished") || defaultValue,
73
+ releasesCreated: trigger.includes("releasesCreated") || defaultValue,
74
+ releasesUpdated: trigger.includes("releasesUpdated") || defaultValue,
75
+ tagsCreated: trigger.includes("tagsCreated") || defaultValue,
76
+ tagsDeleted: trigger.includes("tagsDeleted") || defaultValue,
77
+ },
78
+ { repo, token, host },
79
+ );
80
+ } catch (error) {
81
+ if (error instanceof UnknownRequestError) {
82
+ const message = await error.text();
83
+ throw new CommandError(`Failed to create webhook: ${message}`);
84
+ }
85
+ throw error;
86
+ }
87
+
88
+ console.info(`Webhook created: ${webhookUrl}`);
89
+ });
@@ -0,0 +1,60 @@
1
+ import { getHost, getToken } from "../auth";
2
+ import { getWebhooks, updateWebhook } from "../clients/wroom";
3
+ import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4
+ import { UnknownRequestError } from "../lib/request";
5
+ import { getRepositoryName } from "../project";
6
+
7
+ const config = {
8
+ name: "prismic webhook disable",
9
+ description: `
10
+ Disable a webhook in a Prismic repository.
11
+
12
+ By default, this command reads the repository from prismic.config.json at the
13
+ project root.
14
+ `,
15
+ positionals: {
16
+ url: { description: "Webhook URL" },
17
+ },
18
+ options: {
19
+ repo: { type: "string", short: "r", description: "Repository domain" },
20
+ },
21
+ } satisfies CommandConfig;
22
+
23
+ export default createCommand(config, async ({ positionals, values }) => {
24
+ const [webhookUrl] = positionals;
25
+ const { repo = await getRepositoryName() } = values;
26
+
27
+ if (!webhookUrl) {
28
+ throw new CommandError("Missing required argument: <url>");
29
+ }
30
+
31
+ const token = await getToken();
32
+ const host = await getHost();
33
+ const webhooks = await getWebhooks({ repo, token, host });
34
+ const webhook = webhooks.find((w) => w.config.url === webhookUrl);
35
+ if (!webhook) {
36
+ throw new CommandError(`Webhook not found: ${webhookUrl}`);
37
+ }
38
+
39
+ if (!webhook.config.active) {
40
+ console.info(`Webhook already disabled: ${webhookUrl}`);
41
+ return;
42
+ }
43
+
44
+ const id = webhook.config._id;
45
+
46
+ const updatedConfig = structuredClone(webhook.config);
47
+ updatedConfig.active = false;
48
+
49
+ try {
50
+ await updateWebhook(id, updatedConfig, { repo, token, host });
51
+ } catch (error) {
52
+ if (error instanceof UnknownRequestError) {
53
+ const message = await error.text();
54
+ throw new CommandError(`Failed to disable webhook: ${message}`);
55
+ }
56
+ throw error;
57
+ }
58
+
59
+ console.info(`Webhook disabled: ${webhookUrl}`);
60
+ });
@@ -0,0 +1,60 @@
1
+ import { getHost, getToken } from "../auth";
2
+ import { getWebhooks, updateWebhook } from "../clients/wroom";
3
+ import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4
+ import { UnknownRequestError } from "../lib/request";
5
+ import { getRepositoryName } from "../project";
6
+
7
+ const config = {
8
+ name: "prismic webhook enable",
9
+ description: `
10
+ Enable a webhook in a Prismic repository.
11
+
12
+ By default, this command reads the repository from prismic.config.json at the
13
+ project root.
14
+ `,
15
+ positionals: {
16
+ url: { description: "Webhook URL" },
17
+ },
18
+ options: {
19
+ repo: { type: "string", short: "r", description: "Repository domain" },
20
+ },
21
+ } satisfies CommandConfig;
22
+
23
+ export default createCommand(config, async ({ positionals, values }) => {
24
+ const [webhookUrl] = positionals;
25
+ const { repo = await getRepositoryName() } = values;
26
+
27
+ if (!webhookUrl) {
28
+ throw new CommandError("Missing required argument: <url>");
29
+ }
30
+
31
+ const token = await getToken();
32
+ const host = await getHost();
33
+ const webhooks = await getWebhooks({ repo, token, host });
34
+ const webhook = webhooks.find((w) => w.config.url === webhookUrl);
35
+ if (!webhook) {
36
+ throw new CommandError(`Webhook not found: ${webhookUrl}`);
37
+ }
38
+
39
+ if (webhook.config.active) {
40
+ console.info(`Webhook already enabled: ${webhookUrl}`);
41
+ return;
42
+ }
43
+
44
+ const id = webhook.config._id;
45
+
46
+ const updatedConfig = structuredClone(webhook.config);
47
+ updatedConfig.active = true;
48
+
49
+ try {
50
+ await updateWebhook(id, updatedConfig, { repo, token, host });
51
+ } catch (error) {
52
+ if (error instanceof UnknownRequestError) {
53
+ const message = await error.text();
54
+ throw new CommandError(`Failed to enable webhook: ${message}`);
55
+ }
56
+ throw error;
57
+ }
58
+
59
+ console.info(`Webhook enabled: ${webhookUrl}`);
60
+ });
@@ -0,0 +1,43 @@
1
+ import { getHost, getToken } from "../auth";
2
+ import { getWebhooks } from "../clients/wroom";
3
+ import { createCommand, type CommandConfig } from "../lib/command";
4
+ import { stringify } from "../lib/json";
5
+ import { getRepositoryName } from "../project";
6
+
7
+ const config = {
8
+ name: "prismic webhook list",
9
+ description: `
10
+ List all webhooks in a Prismic repository.
11
+
12
+ By default, this command reads the repository from prismic.config.json at the
13
+ project root.
14
+ `,
15
+ options: {
16
+ json: { type: "boolean", description: "Output as JSON" },
17
+ repo: { type: "string", short: "r", description: "Repository domain" },
18
+ },
19
+ } satisfies CommandConfig;
20
+
21
+ export default createCommand(config, async ({ values }) => {
22
+ const { repo = await getRepositoryName(), json } = values;
23
+
24
+ const token = await getToken();
25
+ const host = await getHost();
26
+ const webhooks = await getWebhooks({ repo, token, host });
27
+
28
+ if (json) {
29
+ console.info(stringify(webhooks.map((webhook) => webhook.config)));
30
+ return;
31
+ }
32
+
33
+ if (webhooks.length === 0) {
34
+ console.info("No webhooks configured.");
35
+ return;
36
+ }
37
+
38
+ for (const webhook of webhooks) {
39
+ const status = webhook.config.active ? "enabled" : "disabled";
40
+ const name = webhook.config.name ? ` (${webhook.config.name})` : "";
41
+ console.info(`${webhook.config.url}${name} [${status}]`);
42
+ }
43
+ });
@@ -0,0 +1,52 @@
1
+ import { getHost, getToken } from "../auth";
2
+ import { deleteWebhook, getWebhooks } from "../clients/wroom";
3
+ import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4
+ import { UnknownRequestError } from "../lib/request";
5
+ import { getRepositoryName } from "../project";
6
+
7
+ const config = {
8
+ name: "prismic webhook remove",
9
+ description: `
10
+ Delete a webhook from a Prismic repository.
11
+
12
+ By default, this command reads the repository from prismic.config.json at the
13
+ project root.
14
+ `,
15
+ positionals: {
16
+ url: { description: "Webhook URL" },
17
+ },
18
+ options: {
19
+ repo: { type: "string", short: "r", description: "Repository domain" },
20
+ },
21
+ } satisfies CommandConfig;
22
+
23
+ export default createCommand(config, async ({ positionals, values }) => {
24
+ const [webhookUrl] = positionals;
25
+ const { repo = await getRepositoryName() } = values;
26
+
27
+ if (!webhookUrl) {
28
+ throw new CommandError("Missing required argument: <url>");
29
+ }
30
+
31
+ const token = await getToken();
32
+ const host = await getHost();
33
+ const webhooks = await getWebhooks({ repo, token, host });
34
+ const webhook = webhooks.find((w) => w.config.url === webhookUrl);
35
+ if (!webhook) {
36
+ throw new CommandError(`Webhook not found: ${webhookUrl}`);
37
+ }
38
+
39
+ const id = webhook.config._id;
40
+
41
+ try {
42
+ await deleteWebhook(id, { repo, token, host });
43
+ } catch (error) {
44
+ if (error instanceof UnknownRequestError) {
45
+ const message = await error.text();
46
+ throw new CommandError(`Failed to remove webhook: ${message}`);
47
+ }
48
+ throw error;
49
+ }
50
+
51
+ console.info(`Webhook removed: ${webhookUrl}`);
52
+ });