@angeloashmore/prismic-cli-poc 0.0.0-canary.2ff9563

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 (119) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +98 -0
  3. package/dist/index.mjs +1996 -0
  4. package/package.json +52 -0
  5. package/src/custom-type-add-field-boolean.ts +171 -0
  6. package/src/custom-type-add-field-color.ts +158 -0
  7. package/src/custom-type-add-field-date.ts +161 -0
  8. package/src/custom-type-add-field-embed.ts +158 -0
  9. package/src/custom-type-add-field-geo-point.ts +155 -0
  10. package/src/custom-type-add-field-image.ts +158 -0
  11. package/src/custom-type-add-field-key-text.ts +158 -0
  12. package/src/custom-type-add-field-link.ts +180 -0
  13. package/src/custom-type-add-field-number.ts +190 -0
  14. package/src/custom-type-add-field-rich-text.ts +181 -0
  15. package/src/custom-type-add-field-select.ts +164 -0
  16. package/src/custom-type-add-field-timestamp.ts +161 -0
  17. package/src/custom-type-add-field-uid.ts +158 -0
  18. package/src/custom-type-add-field.ts +111 -0
  19. package/src/custom-type-connect-slice.ts +221 -0
  20. package/src/custom-type-create.ts +92 -0
  21. package/src/custom-type-disconnect-slice.ts +179 -0
  22. package/src/custom-type-list.ts +110 -0
  23. package/src/custom-type-remove-field.ts +161 -0
  24. package/src/custom-type-remove.ts +126 -0
  25. package/src/custom-type-set-name.ts +128 -0
  26. package/src/custom-type-view.ts +118 -0
  27. package/src/custom-type.ts +85 -0
  28. package/src/index.ts +100 -0
  29. package/src/init.ts +62 -0
  30. package/src/lib/auth.ts +60 -0
  31. package/src/lib/config.ts +111 -0
  32. package/src/lib/file.ts +49 -0
  33. package/src/lib/json.ts +3 -0
  34. package/src/lib/request.ts +116 -0
  35. package/src/lib/slice.ts +112 -0
  36. package/src/lib/url.ts +25 -0
  37. package/src/locale-add.ts +116 -0
  38. package/src/locale-list.ts +107 -0
  39. package/src/locale-remove.ts +88 -0
  40. package/src/locale-set-default.ts +131 -0
  41. package/src/locale.ts +60 -0
  42. package/src/login.ts +143 -0
  43. package/src/logout.ts +36 -0
  44. package/src/page-type-add-field-boolean.ts +171 -0
  45. package/src/page-type-add-field-color.ts +158 -0
  46. package/src/page-type-add-field-date.ts +161 -0
  47. package/src/page-type-add-field-embed.ts +158 -0
  48. package/src/page-type-add-field-geo-point.ts +155 -0
  49. package/src/page-type-add-field-image.ts +158 -0
  50. package/src/page-type-add-field-key-text.ts +158 -0
  51. package/src/page-type-add-field-link.ts +180 -0
  52. package/src/page-type-add-field-number.ts +190 -0
  53. package/src/page-type-add-field-rich-text.ts +181 -0
  54. package/src/page-type-add-field-select.ts +164 -0
  55. package/src/page-type-add-field-timestamp.ts +161 -0
  56. package/src/page-type-add-field-uid.ts +158 -0
  57. package/src/page-type-add-field.ts +111 -0
  58. package/src/page-type-connect-slice.ts +221 -0
  59. package/src/page-type-create.ts +93 -0
  60. package/src/page-type-disconnect-slice.ts +179 -0
  61. package/src/page-type-list.ts +109 -0
  62. package/src/page-type-remove-field.ts +161 -0
  63. package/src/page-type-remove.ts +126 -0
  64. package/src/page-type-set-name.ts +128 -0
  65. package/src/page-type-set-repeatable.ts +137 -0
  66. package/src/page-type-view.ts +118 -0
  67. package/src/page-type.ts +90 -0
  68. package/src/preview-add.ts +126 -0
  69. package/src/preview-list.ts +106 -0
  70. package/src/preview-remove.ts +109 -0
  71. package/src/preview-set-name.ts +137 -0
  72. package/src/preview.ts +60 -0
  73. package/src/repo-create.ts +136 -0
  74. package/src/repo-list.ts +100 -0
  75. package/src/repo-set-name.ts +102 -0
  76. package/src/repo-view.ts +113 -0
  77. package/src/repo.ts +60 -0
  78. package/src/slice-add-field-boolean.ts +150 -0
  79. package/src/slice-add-field-color.ts +137 -0
  80. package/src/slice-add-field-date.ts +137 -0
  81. package/src/slice-add-field-embed.ts +137 -0
  82. package/src/slice-add-field-geo-point.ts +134 -0
  83. package/src/slice-add-field-image.ts +134 -0
  84. package/src/slice-add-field-key-text.ts +137 -0
  85. package/src/slice-add-field-link.ts +155 -0
  86. package/src/slice-add-field-number.ts +137 -0
  87. package/src/slice-add-field-rich-text.ts +160 -0
  88. package/src/slice-add-field-select.ts +143 -0
  89. package/src/slice-add-field-timestamp.ts +137 -0
  90. package/src/slice-add-field.ts +106 -0
  91. package/src/slice-add-variation.ts +137 -0
  92. package/src/slice-create.ts +129 -0
  93. package/src/slice-list-variations.ts +67 -0
  94. package/src/slice-list.ts +88 -0
  95. package/src/slice-remove-field.ts +117 -0
  96. package/src/slice-remove-variation.ts +108 -0
  97. package/src/slice-remove.ts +81 -0
  98. package/src/slice-rename.ts +112 -0
  99. package/src/slice-view.ts +77 -0
  100. package/src/slice.ts +90 -0
  101. package/src/sync.ts +309 -0
  102. package/src/token-create.ts +185 -0
  103. package/src/token-delete.ts +161 -0
  104. package/src/token-list.ts +212 -0
  105. package/src/token-set-name.ts +165 -0
  106. package/src/token.ts +60 -0
  107. package/src/webhook-add-header.ts +118 -0
  108. package/src/webhook-create.ts +152 -0
  109. package/src/webhook-disable.ts +109 -0
  110. package/src/webhook-enable.ts +132 -0
  111. package/src/webhook-list.ts +93 -0
  112. package/src/webhook-remove-header.ts +117 -0
  113. package/src/webhook-remove.ts +106 -0
  114. package/src/webhook-set-triggers.ts +148 -0
  115. package/src/webhook-status.ts +90 -0
  116. package/src/webhook-test.ts +106 -0
  117. package/src/webhook-view.ts +147 -0
  118. package/src/webhook.ts +95 -0
  119. package/src/whoami.ts +62 -0
@@ -0,0 +1,165 @@
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, request, UnauthorizedRequestError } from "./lib/request";
8
+ import { getRepoUrl } from "./lib/url";
9
+ import { getAccessTokens, getWriteTokens, type OAuthApp, OAuthAppSchema, type WriteToken } from "./token-list";
10
+
11
+ const HELP = `
12
+ Set the name of a token in a Prismic repository.
13
+
14
+ Note: Only access tokens can be renamed. Write tokens cannot be renamed without
15
+ changing the token value.
16
+
17
+ By default, this command reads the repository from prismic.config.json at the
18
+ project root.
19
+
20
+ USAGE
21
+ prismic token set-name <token> <name> [flags]
22
+
23
+ ARGUMENTS
24
+ token The token value (or partial match)
25
+ name New name for the token
26
+
27
+ FLAGS
28
+ -r, --repo string Repository domain
29
+ -h, --help Show help for command
30
+
31
+ LEARN MORE
32
+ Use \`prismic token <command> --help\` for more information about a command.
33
+ `.trim();
34
+
35
+ export async function tokenSetName(): Promise<void> {
36
+ const {
37
+ values: { help, repo = await safeGetRepositoryFromConfig() },
38
+ positionals: [tokenValue, newName],
39
+ } = parseArgs({
40
+ args: process.argv.slice(4), // skip: node, script, "token", "set-name"
41
+ options: {
42
+ repo: { type: "string", short: "r" },
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 (!tokenValue) {
54
+ console.error("Missing required argument: token");
55
+ process.exitCode = 1;
56
+ return;
57
+ }
58
+
59
+ if (!newName) {
60
+ console.error("Missing required argument: name");
61
+ process.exitCode = 1;
62
+ return;
63
+ }
64
+
65
+ if (!repo) {
66
+ console.error("Missing prismic.config.json or --repo option");
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+
71
+ const authenticated = await isAuthenticated();
72
+ if (!authenticated) {
73
+ handleUnauthenticated();
74
+ return;
75
+ }
76
+
77
+ // First, find the token in access tokens or write tokens
78
+ const [accessResponse, writeResponse] = await Promise.all([
79
+ getAccessTokens(repo),
80
+ getWriteTokens(repo),
81
+ ]);
82
+
83
+ if (!accessResponse.ok) {
84
+ if (accessResponse.error instanceof ForbiddenRequestError || accessResponse.error instanceof UnauthorizedRequestError) {
85
+ handleUnauthenticated();
86
+ } else if (v.isValiError(accessResponse.error)) {
87
+ console.error(`Failed to list access tokens: Invalid response: ${stringify(accessResponse.error.issues)}`);
88
+ process.exitCode = 1;
89
+ } else {
90
+ console.error(`Failed to list access tokens: ${stringify(accessResponse.value)}`);
91
+ process.exitCode = 1;
92
+ }
93
+ return;
94
+ }
95
+
96
+ if (!writeResponse.ok) {
97
+ if (writeResponse.error instanceof ForbiddenRequestError || writeResponse.error instanceof UnauthorizedRequestError) {
98
+ handleUnauthenticated();
99
+ } else if (v.isValiError(writeResponse.error)) {
100
+ console.error(`Failed to list write tokens: Invalid response: ${stringify(writeResponse.error.issues)}`);
101
+ process.exitCode = 1;
102
+ } else {
103
+ console.error(`Failed to list write tokens: ${stringify(writeResponse.value)}`);
104
+ process.exitCode = 1;
105
+ }
106
+ return;
107
+ }
108
+
109
+ // Find in access tokens
110
+ let foundApp: OAuthApp | undefined;
111
+ for (const app of accessResponse.value) {
112
+ for (const auth of app.wroom_auths) {
113
+ if (auth.token === tokenValue || auth.token.startsWith(tokenValue) || auth.token.endsWith(tokenValue)) {
114
+ foundApp = app;
115
+ break;
116
+ }
117
+ }
118
+ if (foundApp) break;
119
+ }
120
+
121
+ if (foundApp) {
122
+ // Update OAuth app name
123
+ const url = new URL(`settings/security/oauthapp/${foundApp.id}`, await getRepoUrl(repo));
124
+ const response = await request(url, {
125
+ method: "POST",
126
+ body: { name: newName },
127
+ schema: OAuthAppSchema,
128
+ });
129
+
130
+ if (!response.ok) {
131
+ if (response.error instanceof ForbiddenRequestError || response.error instanceof UnauthorizedRequestError) {
132
+ handleUnauthenticated();
133
+ } else if (v.isValiError(response.error)) {
134
+ console.error(`Failed to rename token: Invalid response: ${stringify(response.error.issues)}`);
135
+ process.exitCode = 1;
136
+ } else {
137
+ console.error(`Failed to rename token: ${stringify(response.value)}`);
138
+ process.exitCode = 1;
139
+ }
140
+ return;
141
+ }
142
+
143
+ console.info(`Token renamed to: ${newName}`);
144
+ return;
145
+ }
146
+
147
+ // Check if it's a write token
148
+ const foundWriteToken = writeResponse.value.tokens.find(
149
+ (t: WriteToken) => t.token === tokenValue || t.token.startsWith(tokenValue) || t.token.endsWith(tokenValue),
150
+ );
151
+
152
+ if (foundWriteToken) {
153
+ console.error("Write tokens cannot be renamed. Delete and create a new token with the desired name.");
154
+ process.exitCode = 1;
155
+ return;
156
+ }
157
+
158
+ console.error(`Token not found: ${tokenValue}`);
159
+ process.exitCode = 1;
160
+ }
161
+
162
+ function handleUnauthenticated(): void {
163
+ console.error("Not logged in. Run `prismic login` first.");
164
+ process.exitCode = 1;
165
+ }
package/src/token.ts ADDED
@@ -0,0 +1,60 @@
1
+ import { parseArgs } from "node:util";
2
+
3
+ import { tokenCreate } from "./token-create";
4
+ import { tokenDelete } from "./token-delete";
5
+ import { tokenList } from "./token-list";
6
+ import { tokenSetName } from "./token-set-name";
7
+
8
+ const HELP = `
9
+ Manage API tokens for a Prismic repository.
10
+
11
+ USAGE
12
+ prismic token <command> [flags]
13
+
14
+ COMMANDS
15
+ list List all tokens
16
+ create Create a new token
17
+ set-name Set token name (access tokens only)
18
+ delete Delete a token
19
+
20
+ FLAGS
21
+ -h, --help Show help for command
22
+
23
+ LEARN MORE
24
+ Use \`prismic token <command> --help\` for more information about a command.
25
+ `.trim();
26
+
27
+ export async function token(): Promise<void> {
28
+ const {
29
+ positionals: [subcommand],
30
+ } = parseArgs({
31
+ args: process.argv.slice(3), // skip: node, script, "token"
32
+ options: {
33
+ help: { type: "boolean", short: "h" },
34
+ },
35
+ allowPositionals: true,
36
+ strict: false,
37
+ });
38
+
39
+ switch (subcommand) {
40
+ case "list":
41
+ await tokenList();
42
+ break;
43
+ case "create":
44
+ await tokenCreate();
45
+ break;
46
+ case "set-name":
47
+ await tokenSetName();
48
+ break;
49
+ case "delete":
50
+ await tokenDelete();
51
+ break;
52
+ default: {
53
+ if (subcommand) {
54
+ console.error(`Unknown token subcommand: ${subcommand}\n`);
55
+ process.exitCode = 1;
56
+ }
57
+ console.info(HELP);
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,118 @@
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 } from "./lib/request";
7
+ import { updateWebhook } from "./webhook-enable";
8
+ import { getWebhooks } from "./webhook-view";
9
+
10
+ const HELP = `
11
+ Add a custom HTTP header to a webhook.
12
+
13
+ By default, this command reads the repository from prismic.config.json at the
14
+ project root.
15
+
16
+ USAGE
17
+ prismic webhook add-header <url> <key> <value> [flags]
18
+
19
+ ARGUMENTS
20
+ <url> Webhook URL
21
+ <key> Header name
22
+ <value> Header value
23
+
24
+ FLAGS
25
+ -r, --repo string Repository domain
26
+ -h, --help Show help for command
27
+
28
+ LEARN MORE
29
+ Use \`prismic <command> <subcommand> --help\` for more information about a command.
30
+ `.trim();
31
+
32
+ export async function webhookAddHeader(): Promise<void> {
33
+ const {
34
+ values: { help, repo = await safeGetRepositoryFromConfig() },
35
+ positionals: [webhookUrl, headerKey, headerValue],
36
+ } = parseArgs({
37
+ args: process.argv.slice(4), // skip: node, script, "webhook", "add-header"
38
+ options: {
39
+ repo: { type: "string", short: "r" },
40
+ help: { type: "boolean", short: "h" },
41
+ },
42
+ allowPositionals: true,
43
+ });
44
+
45
+ if (help) {
46
+ console.info(HELP);
47
+ return;
48
+ }
49
+
50
+ if (!webhookUrl) {
51
+ console.error("Missing required argument: <url>");
52
+ process.exitCode = 1;
53
+ return;
54
+ }
55
+
56
+ if (!headerKey) {
57
+ console.error("Missing required argument: <key>");
58
+ process.exitCode = 1;
59
+ return;
60
+ }
61
+
62
+ if (!headerValue) {
63
+ console.error("Missing required argument: <value>");
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+
68
+ if (!repo) {
69
+ console.error("Missing prismic.config.json or --repo option");
70
+ process.exitCode = 1;
71
+ return;
72
+ }
73
+
74
+ const authenticated = await isAuthenticated();
75
+ if (!authenticated) {
76
+ handleUnauthenticated();
77
+ return;
78
+ }
79
+
80
+ const webhooksResponse = await getWebhooks(repo);
81
+ if (!webhooksResponse.ok) {
82
+ if (webhooksResponse.error instanceof ForbiddenRequestError) {
83
+ handleUnauthenticated();
84
+ } else {
85
+ console.error(`Failed to add header: ${stringify(webhooksResponse.value)}`);
86
+ process.exitCode = 1;
87
+ }
88
+ return;
89
+ }
90
+
91
+ const webhook = webhooksResponse.value.find((w) => w.config.url === webhookUrl);
92
+ if (!webhook) {
93
+ console.error(`Webhook not found: ${webhookUrl}`);
94
+ process.exitCode = 1;
95
+ return;
96
+ }
97
+
98
+ const updatedConfig = structuredClone(webhook.config);
99
+ updatedConfig.headers[headerKey] = headerValue;
100
+
101
+ const response = await updateWebhook(repo, webhook.config._id, updatedConfig);
102
+ if (!response.ok) {
103
+ if (response.error instanceof ForbiddenRequestError) {
104
+ handleUnauthenticated();
105
+ } else {
106
+ console.error(`Failed to add header: ${stringify(response.value)}`);
107
+ process.exitCode = 1;
108
+ }
109
+ return;
110
+ }
111
+
112
+ console.info(`Header added: ${headerKey}`);
113
+ }
114
+
115
+ function handleUnauthenticated() {
116
+ console.error("Not logged in. Run `prismic login` first.");
117
+ process.exitCode = 1;
118
+ }
@@ -0,0 +1,152 @@
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
+ import { TRIGGER_DISPLAY, type Webhook } from "./webhook-view";
9
+
10
+ const HELP = `
11
+ Create a new webhook 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 webhook create <url> [flags]
18
+
19
+ ARGUMENTS
20
+ <url> Webhook URL to receive events
21
+
22
+ FLAGS
23
+ -n, --name string Webhook name
24
+ -s, --secret string Secret for webhook signature
25
+ -t, --trigger string Trigger events (can be repeated)
26
+ -r, --repo string Repository domain
27
+ -h, --help Show help for command
28
+
29
+ TRIGGERS
30
+ document.published When documents are published
31
+ document.unpublished When documents are unpublished
32
+ release.created When a release is created
33
+ release.updated When a release is edited or deleted
34
+ tag.created When a tag is created
35
+ tag.deleted When a tag is deleted
36
+
37
+ If no triggers specified, all are enabled.
38
+
39
+ LEARN MORE
40
+ Use \`prismic <command> <subcommand> --help\` for more information about a command.
41
+ `.trim();
42
+
43
+ const VALID_TRIGGERS = Object.values(TRIGGER_DISPLAY);
44
+
45
+ export async function webhookCreate(): Promise<void> {
46
+ const {
47
+ values: { help, repo = await safeGetRepositoryFromConfig(), name, secret, trigger = [] },
48
+ positionals: [webhookUrl],
49
+ } = parseArgs({
50
+ args: process.argv.slice(4), // skip: node, script, "webhook", "create"
51
+ options: {
52
+ name: { type: "string", short: "n" },
53
+ secret: { type: "string", short: "s" },
54
+ trigger: { type: "string", multiple: true, short: "t" },
55
+ repo: { type: "string", short: "r" },
56
+ help: { type: "boolean", short: "h" },
57
+ },
58
+ allowPositionals: true,
59
+ });
60
+
61
+ if (help) {
62
+ console.info(HELP);
63
+ return;
64
+ }
65
+
66
+ if (!webhookUrl) {
67
+ console.error("Missing required argument: <url>");
68
+ process.exitCode = 1;
69
+ return;
70
+ }
71
+
72
+ if (!repo) {
73
+ console.error("Missing prismic.config.json or --repo option");
74
+ process.exitCode = 1;
75
+ return;
76
+ }
77
+
78
+ // Validate triggers
79
+ for (const t of trigger) {
80
+ if (!VALID_TRIGGERS.includes(t)) {
81
+ console.error(`Invalid trigger: ${t}`);
82
+ console.error(`Valid triggers: ${VALID_TRIGGERS.join(", ")}`);
83
+ process.exitCode = 1;
84
+ return;
85
+ }
86
+ }
87
+
88
+ const authenticated = await isAuthenticated();
89
+ if (!authenticated) {
90
+ handleUnauthenticated();
91
+ return;
92
+ }
93
+
94
+ // Build trigger settings
95
+ const defaultValue = trigger.length > 0 ? false : true;
96
+ const triggers: Record<keyof typeof TRIGGER_DISPLAY, boolean> = {
97
+ documentsPublished: defaultValue,
98
+ documentsUnpublished: defaultValue,
99
+ releasesCreated: defaultValue,
100
+ releasesUpdated: defaultValue,
101
+ tagsCreated: defaultValue,
102
+ tagsDeleted: defaultValue,
103
+ };
104
+ for (const t of trigger) {
105
+ const [apiField] = Object.entries(TRIGGER_DISPLAY).find(([, display]) => t === display) ?? [];
106
+ if (!apiField) continue;
107
+ triggers[apiField as keyof typeof TRIGGER_DISPLAY] = true;
108
+ }
109
+
110
+ const response = await createWebhook(repo, {
111
+ url: webhookUrl,
112
+ name: name ?? null,
113
+ secret: secret ?? null,
114
+ ...triggers,
115
+ });
116
+ if (!response.ok) {
117
+ if (response.error instanceof ForbiddenRequestError) {
118
+ handleUnauthenticated();
119
+ } else {
120
+ console.error(`Failed to create webhook: ${stringify(response.value)}`);
121
+ process.exitCode = 1;
122
+ }
123
+ return;
124
+ }
125
+
126
+ console.info(`Webhook created: ${webhookUrl}`);
127
+ }
128
+
129
+ async function createWebhook(
130
+ repo: string,
131
+ config: Omit<Webhook["config"], "_id" | "active" | "headers">,
132
+ ) {
133
+ const url = new URL("/app/settings/webhooks/create", await getRepoUrl(repo));
134
+ const body = new FormData();
135
+ body.set("url", config.url);
136
+ body.set("name", config.name ?? "");
137
+ body.set("secret", config.secret ?? "");
138
+ body.set("headers", JSON.stringify({}));
139
+ body.set("active", "on");
140
+ body.set("documentsPublished", config.documentsUnpublished.toString());
141
+ body.set("documentsUnpublished", config.documentsUnpublished.toString());
142
+ body.set("releasesCreated", config.documentsUnpublished.toString());
143
+ body.set("releasesUpdated", config.documentsUnpublished.toString());
144
+ body.set("tagsCreated", config.documentsUnpublished.toString());
145
+ body.set("documentsPublished", config.documentsUnpublished.toString());
146
+ return await request(url, { method: "POST", body });
147
+ }
148
+
149
+ function handleUnauthenticated() {
150
+ console.error("Not logged in. Run `prismic login` first.");
151
+ process.exitCode = 1;
152
+ }
@@ -0,0 +1,109 @@
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 } from "./lib/request";
7
+ import { updateWebhook } from "./webhook-enable";
8
+ import { getWebhooks } from "./webhook-view";
9
+
10
+ const HELP = `
11
+ Disable a webhook 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 webhook disable <url> [flags]
18
+
19
+ ARGUMENTS
20
+ <url> Webhook URL
21
+
22
+ FLAGS
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 webhookDisable(): Promise<void> {
31
+ const {
32
+ values: { help, repo = await safeGetRepositoryFromConfig() },
33
+ positionals: [webhookUrl],
34
+ } = parseArgs({
35
+ args: process.argv.slice(4), // skip: node, script, "webhook", "disable"
36
+ options: {
37
+ repo: { type: "string", short: "r" },
38
+ help: { type: "boolean", short: "h" },
39
+ },
40
+ allowPositionals: true,
41
+ });
42
+
43
+ if (help) {
44
+ console.info(HELP);
45
+ return;
46
+ }
47
+
48
+ if (!webhookUrl) {
49
+ console.error("Missing required argument: <url>");
50
+ process.exitCode = 1;
51
+ return;
52
+ }
53
+
54
+ if (!repo) {
55
+ console.error("Missing prismic.config.json or --repo option");
56
+ process.exitCode = 1;
57
+ return;
58
+ }
59
+
60
+ const authenticated = await isAuthenticated();
61
+ if (!authenticated) {
62
+ handleUnauthenticated();
63
+ return;
64
+ }
65
+
66
+ const webhooksResponse = await getWebhooks(repo);
67
+ if (!webhooksResponse.ok) {
68
+ if (webhooksResponse.error instanceof ForbiddenRequestError) {
69
+ handleUnauthenticated();
70
+ } else {
71
+ console.error(`Failed to disable webhook: ${stringify(webhooksResponse.value)}`);
72
+ process.exitCode = 1;
73
+ }
74
+ return;
75
+ }
76
+
77
+ const webhook = webhooksResponse.value.find((w) => w.config.url === webhookUrl);
78
+ if (!webhook) {
79
+ console.error(`Webhook not found: ${webhookUrl}`);
80
+ process.exitCode = 1;
81
+ return;
82
+ }
83
+
84
+ if (!webhook.config.active) {
85
+ console.info(`Webhook already disabled: ${webhookUrl}`);
86
+ return;
87
+ }
88
+
89
+ const updatedConfig = structuredClone(webhook.config);
90
+ updatedConfig.active = false;
91
+
92
+ const response = await updateWebhook(repo, webhook.config._id, updatedConfig);
93
+ if (!response.ok) {
94
+ if (response.error instanceof ForbiddenRequestError) {
95
+ handleUnauthenticated();
96
+ } else {
97
+ console.error(`Failed to disable webhook: ${stringify(response.value)}`);
98
+ process.exitCode = 1;
99
+ }
100
+ return;
101
+ }
102
+
103
+ console.info(`Webhook disabled: ${webhookUrl}`);
104
+ }
105
+
106
+ function handleUnauthenticated() {
107
+ console.error("Not logged in. Run `prismic login` first.");
108
+ process.exitCode = 1;
109
+ }