@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,144 @@
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
+ Change a custom type's display name (label).
13
+
14
+ USAGE
15
+ prismic custom-type set-name <type-id> <new-name> [flags]
16
+
17
+ ARGUMENTS
18
+ type-id Custom type identifier (required)
19
+ new-name New display name (required)
20
+
21
+ Types are generated by default after changes. Use --no-types to skip.
22
+
23
+ FLAGS
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
+ EXAMPLES
29
+ prismic custom-type set-name settings "Site Settings"
30
+ prismic custom-type set-name menu "Navigation Menu"
31
+ `.trim();
32
+
33
+ const CustomTypeSchema = v.object({
34
+ id: v.string(),
35
+ label: v.string(),
36
+ repeatable: v.boolean(),
37
+ status: v.boolean(),
38
+ format: v.optional(v.string()),
39
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
40
+ });
41
+
42
+ export async function customTypeSetName(): Promise<void> {
43
+ const {
44
+ values: { help, types, "no-types": noTypes },
45
+ positionals: [typeId, newName],
46
+ } = parseArgs({
47
+ args: process.argv.slice(4), // skip: node, script, "custom-type", "set-name"
48
+ options: {
49
+ types: { type: "string" },
50
+ "no-types": { type: "boolean" },
51
+ help: { type: "boolean", short: "h" },
52
+ },
53
+ allowPositionals: true,
54
+ });
55
+
56
+ if (help) {
57
+ console.info(HELP);
58
+ return;
59
+ }
60
+
61
+ if (!typeId) {
62
+ console.error("Missing required argument: type-id\n");
63
+ console.error("Usage: prismic custom-type set-name <type-id> <new-name>");
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+
68
+ if (!newName) {
69
+ console.error("Missing required argument: new-name\n");
70
+ console.error("Usage: prismic custom-type set-name <type-id> <new-name>");
71
+ process.exitCode = 1;
72
+ return;
73
+ }
74
+
75
+ const projectRoot = await findUpward("package.json");
76
+ if (!projectRoot) {
77
+ console.error("Could not find project root (no package.json found)");
78
+ process.exitCode = 1;
79
+ return;
80
+ }
81
+
82
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
83
+
84
+ // Read and parse the model
85
+ let model: CustomType;
86
+ try {
87
+ const contents = await readFile(modelPath, "utf8");
88
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
89
+ if (!result.success) {
90
+ console.error(`Invalid custom type model: ${modelPath.href}`);
91
+ process.exitCode = 1;
92
+ return;
93
+ }
94
+ model = result.output as CustomType;
95
+ } catch (error) {
96
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
97
+ console.error(`Custom type not found: ${typeId}\n`);
98
+ console.error(`Create it first with: prismic custom-type create ${typeId}`);
99
+ process.exitCode = 1;
100
+ return;
101
+ }
102
+ if (error instanceof Error) {
103
+ console.error(`Failed to read custom type: ${error.message}`);
104
+ } else {
105
+ console.error("Failed to read custom type");
106
+ }
107
+ process.exitCode = 1;
108
+ return;
109
+ }
110
+
111
+ // Check if this is actually a custom type (not a page type)
112
+ if (model.format === "page") {
113
+ console.error(`"${typeId}" is not a custom type (format: page)`);
114
+ process.exitCode = 1;
115
+ return;
116
+ }
117
+
118
+ // Update the model
119
+ model.label = newName;
120
+
121
+ // Write updated model
122
+ try {
123
+ await writeFile(modelPath, stringify(model));
124
+ } catch (error) {
125
+ if (error instanceof Error) {
126
+ console.error(`Failed to update custom type: ${error.message}`);
127
+ } else {
128
+ console.error("Failed to update custom type");
129
+ }
130
+ process.exitCode = 1;
131
+ return;
132
+ }
133
+
134
+ console.info(`Renamed custom type "${typeId}" to "${newName}"`);
135
+
136
+ if (!noTypes) {
137
+ try {
138
+ await buildTypes({ output: types });
139
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
140
+ } catch (error) {
141
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
142
+ }
143
+ }
144
+ }
@@ -0,0 +1,118 @@
1
+ import type { CustomType } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { readFile } from "node:fs/promises";
4
+ import { parseArgs } from "node:util";
5
+ import * as v from "valibot";
6
+
7
+ import { findUpward } from "./lib/file";
8
+
9
+ const HELP = `
10
+ View details of a specific custom type.
11
+
12
+ USAGE
13
+ prismic custom-type view <type-id> [flags]
14
+
15
+ ARGUMENTS
16
+ type-id Custom type identifier (required)
17
+
18
+ FLAGS
19
+ --json Output as JSON
20
+ -h, --help Show help for command
21
+
22
+ EXAMPLES
23
+ prismic custom-type view settings
24
+ prismic custom-type view settings --json
25
+ `.trim();
26
+
27
+ const CustomTypeSchema = v.object({
28
+ id: v.string(),
29
+ label: v.string(),
30
+ repeatable: v.boolean(),
31
+ status: v.boolean(),
32
+ format: v.optional(v.string()),
33
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
34
+ });
35
+
36
+ export async function customTypeView(): Promise<void> {
37
+ const {
38
+ values: { help, json },
39
+ positionals: [typeId],
40
+ } = parseArgs({
41
+ args: process.argv.slice(4), // skip: node, script, "custom-type", "view"
42
+ options: {
43
+ json: { type: "boolean" },
44
+ help: { type: "boolean", short: "h" },
45
+ },
46
+ allowPositionals: true,
47
+ });
48
+
49
+ if (help) {
50
+ console.info(HELP);
51
+ return;
52
+ }
53
+
54
+ if (!typeId) {
55
+ console.error("Missing required argument: type-id\n");
56
+ console.error("Usage: prismic custom-type view <type-id>");
57
+ process.exitCode = 1;
58
+ return;
59
+ }
60
+
61
+ const projectRoot = await findUpward("package.json");
62
+ if (!projectRoot) {
63
+ console.error("Could not find project root (no package.json found)");
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+
68
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
69
+
70
+ let model: CustomType;
71
+ try {
72
+ const contents = await readFile(modelPath, "utf8");
73
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
74
+ if (!result.success) {
75
+ console.error(`Invalid custom type model: ${modelPath.href}`);
76
+ process.exitCode = 1;
77
+ return;
78
+ }
79
+ model = result.output as CustomType;
80
+ } catch (error) {
81
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
82
+ console.error(`Custom type not found: ${typeId}\n`);
83
+ console.error(`Create it first with: prismic custom-type create ${typeId}`);
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+ if (error instanceof Error) {
88
+ console.error(`Failed to read custom type: ${error.message}`);
89
+ } else {
90
+ console.error("Failed to read custom type");
91
+ }
92
+ process.exitCode = 1;
93
+ return;
94
+ }
95
+
96
+ // Check if this is actually a custom type (not a page type)
97
+ if (model.format === "page") {
98
+ console.error(`"${typeId}" is not a custom type (format: page)`);
99
+ process.exitCode = 1;
100
+ return;
101
+ }
102
+
103
+ if (json) {
104
+ console.info(JSON.stringify(model, null, 2));
105
+ return;
106
+ }
107
+
108
+ console.info(`ID: ${model.id}`);
109
+ console.info(`Label: ${model.label}`);
110
+ console.info(`Repeatable: ${model.repeatable}`);
111
+
112
+ const tabs = Object.entries(model.json);
113
+ console.info(`\nTabs (${tabs.length}):`);
114
+ for (const [tabName, tabFields] of tabs) {
115
+ const fieldCount = Object.keys(tabFields).length;
116
+ console.info(` - ${tabName}: ${fieldCount} fields`);
117
+ }
118
+ }
@@ -0,0 +1,85 @@
1
+ import { parseArgs } from "node:util";
2
+
3
+ import { customTypeAddField } from "./custom-type-add-field";
4
+ import { customTypeConnectSlice } from "./custom-type-connect-slice";
5
+ import { customTypeCreate } from "./custom-type-create";
6
+ import { customTypeDisconnectSlice } from "./custom-type-disconnect-slice";
7
+ import { customTypeList } from "./custom-type-list";
8
+ import { customTypeRemove } from "./custom-type-remove";
9
+ import { customTypeRemoveField } from "./custom-type-remove-field";
10
+ import { customTypeSetName } from "./custom-type-set-name";
11
+ import { customTypeView } from "./custom-type-view";
12
+
13
+ const HELP = `
14
+ Manage custom types in a Prismic repository.
15
+
16
+ USAGE
17
+ prismic custom-type <command> [flags]
18
+
19
+ COMMANDS
20
+ create Create a new custom type
21
+ list List all custom types
22
+ view View details of a custom type
23
+ remove Remove a custom type
24
+ set-name Change a custom type's display name
25
+ add-field Add a field to a custom type
26
+ remove-field Remove a field from a custom type
27
+ connect-slice Connect a shared slice to a custom type
28
+ disconnect-slice Disconnect a shared slice from a custom type
29
+
30
+ FLAGS
31
+ -h, --help Show help for command
32
+
33
+ LEARN MORE
34
+ Use \`prismic custom-type <command> --help\` for more information about a command.
35
+ `.trim();
36
+
37
+ export async function customType(): Promise<void> {
38
+ const {
39
+ positionals: [subcommand],
40
+ } = parseArgs({
41
+ args: process.argv.slice(3), // skip: node, script, "custom-type"
42
+ options: {
43
+ help: { type: "boolean", short: "h" },
44
+ },
45
+ allowPositionals: true,
46
+ strict: false,
47
+ });
48
+
49
+ switch (subcommand) {
50
+ case "create":
51
+ await customTypeCreate();
52
+ break;
53
+ case "list":
54
+ await customTypeList();
55
+ break;
56
+ case "view":
57
+ await customTypeView();
58
+ break;
59
+ case "remove":
60
+ await customTypeRemove();
61
+ break;
62
+ case "set-name":
63
+ await customTypeSetName();
64
+ break;
65
+ case "add-field":
66
+ await customTypeAddField();
67
+ break;
68
+ case "remove-field":
69
+ await customTypeRemoveField();
70
+ break;
71
+ case "connect-slice":
72
+ await customTypeConnectSlice();
73
+ break;
74
+ case "disconnect-slice":
75
+ await customTypeDisconnectSlice();
76
+ break;
77
+ default: {
78
+ if (subcommand) {
79
+ console.error(`Unknown custom-type subcommand: ${subcommand}\n`);
80
+ process.exitCode = 1;
81
+ }
82
+ console.info(HELP);
83
+ }
84
+ }
85
+ }
package/src/index.ts ADDED
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { parseArgs } from "node:util";
4
+
5
+ import packageJson from "../package.json" with { type: "json" };
6
+ import { codegen } from "./codegen";
7
+ import { customType } from "./custom-type";
8
+ import { init } from "./init";
9
+ import { locale } from "./locale";
10
+ import { login } from "./login";
11
+ import { logout } from "./logout";
12
+ import { pageType } from "./page-type";
13
+ import { preview } from "./preview";
14
+ import { pull } from "./pull";
15
+ import { push } from "./push";
16
+ import { repo } from "./repo";
17
+ import { slice } from "./slice";
18
+ import { status } from "./status";
19
+ import { token } from "./token";
20
+ import { webhook } from "./webhook";
21
+ import { whoami } from "./whoami";
22
+
23
+ const HELP = `
24
+ Prismic CLI for managing repositories and configurations.
25
+
26
+ USAGE
27
+ prismic <command> [flags]
28
+
29
+ COMMANDS
30
+ init Initialize a Prismic project
31
+ login Log in to Prismic
32
+ logout Log out of Prismic
33
+ whoami Show the currently logged in user
34
+ status Show the status of the current project
35
+ repo Manage Prismic repositories
36
+ locale Manage locales in a repository
37
+ page-type Manage page types in a repository
38
+ custom-type Manage custom types in a repository
39
+ slice Manage slices in a project
40
+ pull Pull types and slices from Prismic
41
+ push Push types and slices to Prismic
42
+ codegen Generate code from Prismic models
43
+ preview Manage preview configurations
44
+ token Manage API tokens in a repository
45
+ webhook Manage webhooks in a repository
46
+
47
+ FLAGS
48
+ -v, --version Show CLI version
49
+ -h, --help Show help for command
50
+
51
+ LEARN MORE
52
+ Use \`prismic <command> --help\` for more information about a command.
53
+ `.trim();
54
+
55
+ const {
56
+ positionals,
57
+ values: { version },
58
+ } = parseArgs({
59
+ options: {
60
+ help: { type: "boolean", short: "h" },
61
+ version: { type: "boolean", short: "v" },
62
+ },
63
+ allowPositionals: true,
64
+ strict: false,
65
+ });
66
+
67
+ if (version) {
68
+ console.info(packageJson.version);
69
+ } else {
70
+ switch (positionals[0]) {
71
+ case "init":
72
+ await init();
73
+ break;
74
+ case "login":
75
+ await login();
76
+ break;
77
+ case "logout":
78
+ await logout();
79
+ break;
80
+ case "whoami":
81
+ await whoami();
82
+ break;
83
+ case "status":
84
+ await status();
85
+ break;
86
+ case "repo":
87
+ await repo();
88
+ break;
89
+ case "locale":
90
+ await locale();
91
+ break;
92
+ case "page-type":
93
+ await pageType();
94
+ break;
95
+ case "custom-type":
96
+ await customType();
97
+ break;
98
+ case "slice":
99
+ await slice();
100
+ break;
101
+ case "pull":
102
+ await pull();
103
+ break;
104
+ case "push":
105
+ await push();
106
+ break;
107
+ case "codegen":
108
+ await codegen();
109
+ break;
110
+ case "preview":
111
+ await preview();
112
+ break;
113
+ case "token":
114
+ await token();
115
+ break;
116
+ case "webhook":
117
+ await webhook();
118
+ break;
119
+ default: {
120
+ if (positionals[0]) {
121
+ console.error(`Unknown command: ${positionals[0]}`);
122
+ process.exitCode = 1;
123
+ }
124
+ console.info(HELP);
125
+ }
126
+ }
127
+ }
package/src/init.ts ADDED
@@ -0,0 +1,64 @@
1
+ import { parseArgs } from "node:util";
2
+
3
+ import { createConfig, readConfig, UnknownProjectRoot } from "./lib/config";
4
+
5
+ const HELP = `
6
+ Initialize a Prismic project by creating a prismic.config.json file.
7
+
8
+ Use this command to connect an existing Prismic repository to your project.
9
+ To create a new repository, use \`prismic repo create\` instead.
10
+
11
+ USAGE
12
+ prismic init [flags]
13
+
14
+ FLAGS
15
+ -r, --repo Repository name (required)
16
+ -h, --help Show help for command
17
+
18
+ LEARN MORE
19
+ Use \`prismic <command> --help\` for more information about a command.
20
+ `.trim();
21
+
22
+ export async function init(): Promise<void> {
23
+ const { values } = parseArgs({
24
+ args: process.argv.slice(3),
25
+ options: {
26
+ help: { type: "boolean", short: "h" },
27
+ repo: { type: "string", short: "r" },
28
+ },
29
+ });
30
+
31
+ if (values.help) {
32
+ console.info(HELP);
33
+ return;
34
+ }
35
+
36
+ if (!values.repo) {
37
+ console.error("Missing required flag: --repo");
38
+ process.exitCode = 1;
39
+ return;
40
+ }
41
+
42
+ const existingConfig = await readConfig();
43
+ if (existingConfig.ok) {
44
+ console.error("A prismic.config.json file already exists.");
45
+ process.exitCode = 1;
46
+ return;
47
+ }
48
+
49
+ const result = await createConfig({ repositoryName: values.repo });
50
+
51
+ if (!result.ok) {
52
+ if (result.error instanceof UnknownProjectRoot) {
53
+ console.error(
54
+ "Could not find a package.json file. Run this command from a project directory.",
55
+ );
56
+ } else {
57
+ console.error("Failed to create config file.");
58
+ }
59
+ process.exitCode = 1;
60
+ return;
61
+ }
62
+
63
+ console.info(`Created prismic.config.json for repository "${values.repo}"`);
64
+ }
@@ -0,0 +1,83 @@
1
+ import { access, readFile, rm, writeFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { pathToFileURL } from "node:url";
4
+
5
+ import { appendTrailingSlash } from "./url";
6
+
7
+ const AUTH_FILE_PATH = new URL(".prismic", appendTrailingSlash(pathToFileURL(homedir())));
8
+ const DEFAULT_HOST = "https://prismic.io";
9
+
10
+ type AuthContents = {
11
+ token?: string;
12
+ host?: string;
13
+ };
14
+
15
+ export async function saveToken(token: string, options?: { host?: string }): Promise<void> {
16
+ const contents: AuthContents = { token, host: options?.host };
17
+ await writeFile(AUTH_FILE_PATH, JSON.stringify(contents, null, 2));
18
+ }
19
+
20
+ export async function isAuthenticated(): Promise<boolean> {
21
+ const token = await readToken();
22
+ if (!token) return false;
23
+
24
+ // Verify token is still valid by calling the profile endpoint
25
+ try {
26
+ const host = await readHost();
27
+ host.hostname = `user-service.${host.hostname}`;
28
+ const url = new URL("profile", host);
29
+
30
+ const response = await fetch(url, {
31
+ headers: {
32
+ Accept: "application/json",
33
+ Cookie: `SESSION=fake_session; prismic-auth=${token}`,
34
+ },
35
+ });
36
+
37
+ if (!response.ok) {
38
+ await removeToken();
39
+ return false;
40
+ }
41
+
42
+ return true;
43
+ } catch {
44
+ return false;
45
+ }
46
+ }
47
+
48
+ export async function readToken(): Promise<string | undefined> {
49
+ const auth = await readAuthFile();
50
+ return auth?.token;
51
+ }
52
+
53
+ export async function readHost(): Promise<URL> {
54
+ try {
55
+ const auth = await readAuthFile();
56
+ if (!auth?.host) return new URL(DEFAULT_HOST);
57
+ return new URL(auth.host);
58
+ } catch {
59
+ return new URL(DEFAULT_HOST);
60
+ }
61
+ }
62
+
63
+ async function readAuthFile(): Promise<AuthContents | undefined> {
64
+ try {
65
+ const contents = await readFile(AUTH_FILE_PATH, "utf-8");
66
+ return JSON.parse(contents);
67
+ } catch {
68
+ return undefined;
69
+ }
70
+ }
71
+
72
+ export async function removeToken(): Promise<boolean> {
73
+ try {
74
+ await access(AUTH_FILE_PATH);
75
+ } catch {
76
+ return true;
77
+ }
78
+
79
+ const auth = await readAuthFile();
80
+ if (!auth) return false;
81
+ await rm(AUTH_FILE_PATH);
82
+ return true;
83
+ }