prismic 0.0.0-pr.28.59bf330

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 (158) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +69 -0
  3. package/dist/builders-hKD4IrLX-DsO7BUQw.mjs +97 -0
  4. package/dist/dist-B11B2hHn.mjs +1 -0
  5. package/dist/dist-DT8CtumB.mjs +1 -0
  6. package/dist/framework-CfjEoVk0.mjs +17 -0
  7. package/dist/index.mjs +2537 -0
  8. package/dist/nextjs-9z7YrSnS.mjs +312 -0
  9. package/dist/nuxt-KoJ61G2q.mjs +59 -0
  10. package/dist/sveltekit-DjXKCG78.mjs +226 -0
  11. package/package.json +58 -0
  12. package/src/codegen-types.ts +82 -0
  13. package/src/codegen.ts +45 -0
  14. package/src/custom-type-add-field-boolean.ts +185 -0
  15. package/src/custom-type-add-field-color.ts +168 -0
  16. package/src/custom-type-add-field-date.ts +171 -0
  17. package/src/custom-type-add-field-embed.ts +168 -0
  18. package/src/custom-type-add-field-geo-point.ts +165 -0
  19. package/src/custom-type-add-field-group.ts +142 -0
  20. package/src/custom-type-add-field-image.ts +168 -0
  21. package/src/custom-type-add-field-key-text.ts +168 -0
  22. package/src/custom-type-add-field-link.ts +191 -0
  23. package/src/custom-type-add-field-number.ts +200 -0
  24. package/src/custom-type-add-field-rich-text.ts +192 -0
  25. package/src/custom-type-add-field-select.ts +174 -0
  26. package/src/custom-type-add-field-timestamp.ts +171 -0
  27. package/src/custom-type-add-field-uid.ts +151 -0
  28. package/src/custom-type-add-field.ts +116 -0
  29. package/src/custom-type-connect-slice.ts +178 -0
  30. package/src/custom-type-create.ts +98 -0
  31. package/src/custom-type-disconnect-slice.ts +134 -0
  32. package/src/custom-type-list.ts +110 -0
  33. package/src/custom-type-remove-field.ts +135 -0
  34. package/src/custom-type-remove.ts +103 -0
  35. package/src/custom-type-set-name.ts +102 -0
  36. package/src/custom-type-view.ts +118 -0
  37. package/src/custom-type.ts +85 -0
  38. package/src/docs-fetch.ts +146 -0
  39. package/src/docs-list.ts +131 -0
  40. package/src/docs.ts +54 -0
  41. package/src/env.d.ts +12 -0
  42. package/src/framework/index.ts +399 -0
  43. package/src/framework/nextjs.templates.ts +426 -0
  44. package/src/framework/nextjs.ts +216 -0
  45. package/src/framework/nuxt.templates.ts +74 -0
  46. package/src/framework/nuxt.ts +250 -0
  47. package/src/framework/sveltekit.templates.ts +278 -0
  48. package/src/framework/sveltekit.ts +241 -0
  49. package/src/index.ts +155 -0
  50. package/src/init.ts +173 -0
  51. package/src/lib/auth.ts +200 -0
  52. package/src/lib/browser.ts +11 -0
  53. package/src/lib/config.ts +111 -0
  54. package/src/lib/custom-types-api.ts +385 -0
  55. package/src/lib/field-path.ts +81 -0
  56. package/src/lib/file.ts +49 -0
  57. package/src/lib/json.ts +3 -0
  58. package/src/lib/packageJson.ts +35 -0
  59. package/src/lib/profile.ts +39 -0
  60. package/src/lib/request.ts +116 -0
  61. package/src/lib/segment.ts +145 -0
  62. package/src/lib/sentry.ts +63 -0
  63. package/src/lib/string.ts +10 -0
  64. package/src/lib/url.ts +31 -0
  65. package/src/locale-add.ts +116 -0
  66. package/src/locale-list.ts +107 -0
  67. package/src/locale-remove.ts +88 -0
  68. package/src/locale-set-default.ts +131 -0
  69. package/src/locale.ts +60 -0
  70. package/src/login.ts +45 -0
  71. package/src/logout.ts +36 -0
  72. package/src/page-type-add-field-boolean.ts +179 -0
  73. package/src/page-type-add-field-color.ts +165 -0
  74. package/src/page-type-add-field-date.ts +168 -0
  75. package/src/page-type-add-field-embed.ts +165 -0
  76. package/src/page-type-add-field-geo-point.ts +162 -0
  77. package/src/page-type-add-field-group.ts +139 -0
  78. package/src/page-type-add-field-image.ts +165 -0
  79. package/src/page-type-add-field-key-text.ts +165 -0
  80. package/src/page-type-add-field-link.ts +188 -0
  81. package/src/page-type-add-field-number.ts +197 -0
  82. package/src/page-type-add-field-rich-text.ts +189 -0
  83. package/src/page-type-add-field-select.ts +171 -0
  84. package/src/page-type-add-field-timestamp.ts +168 -0
  85. package/src/page-type-add-field-uid.ts +148 -0
  86. package/src/page-type-add-field.ts +116 -0
  87. package/src/page-type-connect-slice.ts +178 -0
  88. package/src/page-type-create.ts +128 -0
  89. package/src/page-type-disconnect-slice.ts +134 -0
  90. package/src/page-type-list.ts +109 -0
  91. package/src/page-type-remove-field.ts +135 -0
  92. package/src/page-type-remove.ts +103 -0
  93. package/src/page-type-set-name.ts +102 -0
  94. package/src/page-type-set-repeatable.ts +111 -0
  95. package/src/page-type-view.ts +118 -0
  96. package/src/page-type.ts +90 -0
  97. package/src/preview-add.ts +126 -0
  98. package/src/preview-get-simulator.ts +104 -0
  99. package/src/preview-list.ts +106 -0
  100. package/src/preview-remove-simulator.ts +80 -0
  101. package/src/preview-remove.ts +109 -0
  102. package/src/preview-set-name.ts +137 -0
  103. package/src/preview-set-simulator.ts +116 -0
  104. package/src/preview.ts +75 -0
  105. package/src/pull.ts +236 -0
  106. package/src/push.ts +409 -0
  107. package/src/repo-create.ts +175 -0
  108. package/src/repo-get-access.ts +86 -0
  109. package/src/repo-list.ts +100 -0
  110. package/src/repo-set-access.ts +100 -0
  111. package/src/repo-set-name.ts +102 -0
  112. package/src/repo-view.ts +113 -0
  113. package/src/repo.ts +70 -0
  114. package/src/slice-add-field-boolean.ts +219 -0
  115. package/src/slice-add-field-color.ts +205 -0
  116. package/src/slice-add-field-date.ts +205 -0
  117. package/src/slice-add-field-embed.ts +205 -0
  118. package/src/slice-add-field-geo-point.ts +202 -0
  119. package/src/slice-add-field-group.ts +170 -0
  120. package/src/slice-add-field-image.ts +202 -0
  121. package/src/slice-add-field-key-text.ts +205 -0
  122. package/src/slice-add-field-link.ts +224 -0
  123. package/src/slice-add-field-number.ts +205 -0
  124. package/src/slice-add-field-rich-text.ts +229 -0
  125. package/src/slice-add-field-select.ts +211 -0
  126. package/src/slice-add-field-timestamp.ts +205 -0
  127. package/src/slice-add-field.ts +111 -0
  128. package/src/slice-add-variation.ts +142 -0
  129. package/src/slice-create.ts +164 -0
  130. package/src/slice-list-variations.ts +71 -0
  131. package/src/slice-list.ts +60 -0
  132. package/src/slice-remove-field.ts +125 -0
  133. package/src/slice-remove-variation.ts +113 -0
  134. package/src/slice-remove.ts +92 -0
  135. package/src/slice-rename.ts +104 -0
  136. package/src/slice-set-screenshot.ts +239 -0
  137. package/src/slice-view.ts +83 -0
  138. package/src/slice.ts +95 -0
  139. package/src/status.ts +834 -0
  140. package/src/sync.ts +259 -0
  141. package/src/token-create.ts +203 -0
  142. package/src/token-delete.ts +182 -0
  143. package/src/token-list.ts +223 -0
  144. package/src/token-set-name.ts +193 -0
  145. package/src/token.ts +60 -0
  146. package/src/webhook-add-header.ts +118 -0
  147. package/src/webhook-create.ts +152 -0
  148. package/src/webhook-disable.ts +109 -0
  149. package/src/webhook-enable.ts +132 -0
  150. package/src/webhook-list.ts +93 -0
  151. package/src/webhook-remove-header.ts +117 -0
  152. package/src/webhook-remove.ts +106 -0
  153. package/src/webhook-set-triggers.ts +148 -0
  154. package/src/webhook-status.ts +90 -0
  155. package/src/webhook-test.ts +106 -0
  156. package/src/webhook-view.ts +147 -0
  157. package/src/webhook.ts +95 -0
  158. package/src/whoami.ts +62 -0
package/src/pull.ts ADDED
@@ -0,0 +1,236 @@
1
+ import { pascalCase } from "change-case";
2
+ import { parseArgs } from "node:util";
3
+
4
+ import { buildTypes } from "./codegen-types";
5
+ import { isAuthenticated } from "./lib/auth";
6
+ import { safeGetRepositoryFromConfig } from "./lib/config";
7
+ import { fetchRemoteCustomTypes, fetchRemoteSlices } from "./lib/custom-types-api";
8
+ import { requireFramework } from "./framework";
9
+ import { stringify } from "./lib/json";
10
+
11
+ const HELP = `
12
+ Pull custom types and slices from Prismic to local files.
13
+
14
+ By default, this command reads the repository from prismic.config.json at the
15
+ project root.
16
+
17
+ USAGE
18
+ prismic pull [flags]
19
+
20
+ FLAGS
21
+ -r, --repo string Repository domain
22
+ --dry-run Show what would be pulled without writing files
23
+ --types-only Only pull custom types
24
+ --slices-only Only pull slices
25
+ --json Output as JSON
26
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
27
+ -h, --help Show help for command
28
+
29
+ EXAMPLES
30
+ prismic pull
31
+ prismic pull --repo my-repo
32
+ prismic pull --dry-run
33
+ prismic pull --types-only
34
+ `.trim();
35
+
36
+ export async function pull(): Promise<void> {
37
+ const {
38
+ values: {
39
+ help,
40
+ repo = await safeGetRepositoryFromConfig(),
41
+ "dry-run": dryRun,
42
+ "types-only": typesOnly,
43
+ "slices-only": slicesOnly,
44
+ json,
45
+ types,
46
+ },
47
+ } = parseArgs({
48
+ args: process.argv.slice(3), // skip: node, script, "pull"
49
+ options: {
50
+ repo: { type: "string", short: "r" },
51
+ "dry-run": { type: "boolean" },
52
+ "types-only": { type: "boolean" },
53
+ "slices-only": { type: "boolean" },
54
+ json: { type: "boolean" },
55
+ types: { type: "string" },
56
+ help: { type: "boolean", short: "h" },
57
+ },
58
+ allowPositionals: false,
59
+ });
60
+
61
+ if (help) {
62
+ console.info(HELP);
63
+ return;
64
+ }
65
+
66
+ if (!repo) {
67
+ console.error("Missing prismic.config.json or --repo option");
68
+ process.exitCode = 1;
69
+ return;
70
+ }
71
+
72
+ // Check authentication
73
+ if (!(await isAuthenticated())) {
74
+ console.error("Not logged in. Run `prismic login` first.");
75
+ process.exitCode = 1;
76
+ return;
77
+ }
78
+
79
+ if (!json) {
80
+ console.info(`Pulling from repository: ${repo}\n`);
81
+ }
82
+
83
+ // Fetch remote data in parallel
84
+ const shouldFetchTypes = !slicesOnly;
85
+ const shouldFetchSlices = !typesOnly;
86
+
87
+ const [customTypesResult, slicesResult] = await Promise.all([
88
+ shouldFetchTypes
89
+ ? fetchRemoteCustomTypes(repo)
90
+ : Promise.resolve({ ok: true, value: [] } as const),
91
+ shouldFetchSlices ? fetchRemoteSlices(repo) : Promise.resolve({ ok: true, value: [] } as const),
92
+ ]);
93
+
94
+ if (!customTypesResult.ok) {
95
+ console.error(`Failed to fetch custom types: ${customTypesResult.error}`);
96
+ process.exitCode = 1;
97
+ return;
98
+ }
99
+
100
+ if (!slicesResult.ok) {
101
+ console.error(`Failed to fetch slices: ${slicesResult.error}`);
102
+ process.exitCode = 1;
103
+ return;
104
+ }
105
+
106
+ const customTypes = customTypesResult.value;
107
+ const slices = slicesResult.value;
108
+
109
+ if (!json) {
110
+ if (shouldFetchTypes) {
111
+ console.info(`Fetching custom types... ${customTypes.length} types`);
112
+ }
113
+ if (shouldFetchSlices) {
114
+ console.info(`Fetching slices... ${slices.length} slices`);
115
+ }
116
+ }
117
+
118
+ // Get framework adapter
119
+ const framework = await requireFramework();
120
+ if (!framework) return;
121
+
122
+ // Dry run - just show what would be pulled
123
+ if (dryRun) {
124
+ if (json) {
125
+ console.info(stringify({ customTypes, slices }));
126
+ } else {
127
+ console.info("");
128
+ if (shouldFetchTypes && customTypes.length > 0) {
129
+ console.info("Would write custom types:");
130
+ for (const ct of customTypes) {
131
+ console.info(` customtypes/${ct.id}/index.json`);
132
+ }
133
+ }
134
+ if (shouldFetchSlices && slices.length > 0) {
135
+ const slicesDir = await framework.getDefaultSliceLibrary();
136
+ const relativeSlicesDir = getRelativePath(slicesDir);
137
+ console.info("Would write slices:");
138
+ for (const slice of slices) {
139
+ console.info(` ${relativeSlicesDir}${pascalCase(slice.name)}/model.json`);
140
+ }
141
+ }
142
+ console.info(
143
+ `\nDry run complete: ${customTypes.length} custom types, ${slices.length} slices`,
144
+ );
145
+ }
146
+ return;
147
+ }
148
+
149
+ // Get existing local slices to determine create vs update
150
+ const existingSlices = await framework.getSlices();
151
+ const existingSliceIds = new Set(existingSlices.map((s) => s.model.id));
152
+ const defaultLibrary = await framework.getDefaultSliceLibrary();
153
+
154
+ const writtenTypes: string[] = [];
155
+ const writtenSlices: string[] = [];
156
+
157
+ // Write custom types
158
+ if (shouldFetchTypes && customTypes.length > 0) {
159
+ if (!json) {
160
+ console.info("\nWriting custom types:");
161
+ }
162
+
163
+ for (const ct of customTypes) {
164
+ try {
165
+ await framework.updateCustomType(ct);
166
+ const relativePath = `customtypes/${ct.id}/index.json`;
167
+ writtenTypes.push(relativePath);
168
+ if (!json) {
169
+ console.info(` ${relativePath}`);
170
+ }
171
+ } catch (error) {
172
+ console.error(
173
+ `Failed to write custom type ${ct.id}: ${error instanceof Error ? error.message : error}`,
174
+ );
175
+ process.exitCode = 1;
176
+ return;
177
+ }
178
+ }
179
+ }
180
+
181
+ // Write slices
182
+ if (shouldFetchSlices && slices.length > 0) {
183
+ if (!json) {
184
+ console.info("\nWriting slices:");
185
+ }
186
+ const slicesDir = await framework.getDefaultSliceLibrary();
187
+
188
+ for (const slice of slices) {
189
+ try {
190
+ if (existingSliceIds.has(slice.id)) {
191
+ await framework.updateSlice(slice);
192
+ } else {
193
+ await framework.createSlice(slice, defaultLibrary);
194
+ }
195
+ const relativePath = `${getRelativePath(slicesDir)}${pascalCase(slice.name)}/model.json`;
196
+ writtenSlices.push(relativePath);
197
+ if (!json) {
198
+ console.info(` ${relativePath}`);
199
+ }
200
+ } catch (error) {
201
+ console.error(
202
+ `Failed to write slice ${slice.name}: ${error instanceof Error ? error.message : error}`,
203
+ );
204
+ process.exitCode = 1;
205
+ return;
206
+ }
207
+ }
208
+ }
209
+
210
+ // Output summary
211
+ if (json) {
212
+ console.info(stringify({ writtenTypes, writtenSlices }));
213
+ } else {
214
+ console.info(
215
+ `\nPull complete: ${writtenTypes.length} custom types, ${writtenSlices.length} slices`,
216
+ );
217
+ }
218
+
219
+ if (!json) {
220
+ try {
221
+ await buildTypes({ output: types, framework });
222
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
223
+ } catch (error) {
224
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
225
+ }
226
+ }
227
+ }
228
+
229
+ function getRelativePath(url: URL): string {
230
+ const cwd = process.cwd();
231
+ const path = url.pathname;
232
+ if (path.startsWith(cwd)) {
233
+ return path.slice(cwd.length + 1);
234
+ }
235
+ return path;
236
+ }
package/src/push.ts ADDED
@@ -0,0 +1,409 @@
1
+ import type { CustomType, SharedSlice } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { parseArgs } from "node:util";
4
+
5
+ import { isAuthenticated } from "./lib/auth";
6
+ import { safeGetRepositoryFromConfig } from "./lib/config";
7
+ import {
8
+ deleteCustomType,
9
+ deleteSlice,
10
+ fetchRemoteCustomTypes,
11
+ fetchRemoteSlices,
12
+ insertCustomType,
13
+ insertSlice,
14
+ updateCustomType,
15
+ updateSlice,
16
+ } from "./lib/custom-types-api";
17
+ import { requireFramework } from "./framework";
18
+ import { stringify } from "./lib/json";
19
+
20
+ const HELP = `
21
+ Push custom types and slices to Prismic from local files.
22
+
23
+ By default, this command reads the repository from prismic.config.json at the
24
+ project root.
25
+
26
+ USAGE
27
+ prismic push [flags]
28
+
29
+ FLAGS
30
+ -r, --repo string Repository domain
31
+ --dry-run Show what would be pushed without making changes
32
+ --types-only Only push custom types
33
+ --slices-only Only push slices
34
+ --delete Delete remote models that don't exist locally (dangerous)
35
+ --json Output as JSON
36
+ -h, --help Show help for command
37
+
38
+ EXAMPLES
39
+ prismic push
40
+ prismic push --repo my-repo
41
+ prismic push --dry-run
42
+ prismic push --types-only
43
+ prismic push --delete
44
+ `.trim();
45
+
46
+ type DiffResult<T> = {
47
+ toInsert: T[];
48
+ toUpdate: T[];
49
+ toDelete: string[];
50
+ };
51
+
52
+ function computeDiff<T extends { id: string }>(local: T[], remote: T[]): DiffResult<T> {
53
+ const localById = new Map(local.map((item) => [item.id, item]));
54
+ const remoteById = new Map(remote.map((item) => [item.id, item]));
55
+
56
+ const toInsert: T[] = [];
57
+ const toUpdate: T[] = [];
58
+ const toDelete: string[] = [];
59
+
60
+ // Find items to insert or update
61
+ for (const localItem of local) {
62
+ const remoteItem = remoteById.get(localItem.id);
63
+ if (!remoteItem) {
64
+ toInsert.push(localItem);
65
+ } else if (JSON.stringify(localItem) !== JSON.stringify(remoteItem)) {
66
+ toUpdate.push(localItem);
67
+ }
68
+ }
69
+
70
+ // Find items to delete (remote IDs not in local)
71
+ for (const remoteItem of remote) {
72
+ if (!localById.has(remoteItem.id)) {
73
+ toDelete.push(remoteItem.id);
74
+ }
75
+ }
76
+
77
+ return { toInsert, toUpdate, toDelete };
78
+ }
79
+
80
+ export async function push(): Promise<void> {
81
+ const {
82
+ values: {
83
+ help,
84
+ repo = await safeGetRepositoryFromConfig(),
85
+ "dry-run": dryRun,
86
+ "types-only": typesOnly,
87
+ "slices-only": slicesOnly,
88
+ delete: deleteRemote,
89
+ json,
90
+ },
91
+ } = parseArgs({
92
+ args: process.argv.slice(3), // skip: node, script, "push"
93
+ options: {
94
+ repo: { type: "string", short: "r" },
95
+ "dry-run": { type: "boolean" },
96
+ "types-only": { type: "boolean" },
97
+ "slices-only": { type: "boolean" },
98
+ delete: { type: "boolean" },
99
+ json: { type: "boolean" },
100
+ help: { type: "boolean", short: "h" },
101
+ },
102
+ allowPositionals: false,
103
+ });
104
+
105
+ if (help) {
106
+ console.info(HELP);
107
+ return;
108
+ }
109
+
110
+ if (!repo) {
111
+ console.error("Missing prismic.config.json or --repo option");
112
+ process.exitCode = 1;
113
+ return;
114
+ }
115
+
116
+ // Check authentication
117
+ if (!(await isAuthenticated())) {
118
+ console.error("Not logged in. Run `prismic login` first.");
119
+ process.exitCode = 1;
120
+ return;
121
+ }
122
+
123
+ if (!json) {
124
+ console.info(`Pushing to repository: ${repo}\n`);
125
+ }
126
+
127
+ const shouldPushTypes = !slicesOnly;
128
+ const shouldPushSlices = !typesOnly;
129
+
130
+ // Get framework adapter for reading local models
131
+ const framework = await requireFramework();
132
+ if (!framework) return;
133
+
134
+ // Read local models via framework adapter
135
+ let localTypes: CustomType[];
136
+ let localSlices: SharedSlice[];
137
+ try {
138
+ const [localCustomTypeResults, localSliceResults] = await Promise.all([
139
+ shouldPushTypes ? framework.getCustomTypes() : Promise.resolve([]),
140
+ shouldPushSlices ? framework.getSlices() : Promise.resolve([]),
141
+ ]);
142
+ localTypes = localCustomTypeResults.map((ct) => ct.model as unknown as CustomType);
143
+ localSlices = localSliceResults.map((s) => s.model as unknown as SharedSlice);
144
+ } catch (error) {
145
+ console.error(
146
+ `Failed to read local models: ${error instanceof Error ? error.message : error}`,
147
+ );
148
+ process.exitCode = 1;
149
+ return;
150
+ }
151
+
152
+ // Fetch remote data in parallel
153
+ const [remoteTypesResult, remoteSlicesResult] = await Promise.all([
154
+ shouldPushTypes
155
+ ? fetchRemoteCustomTypes(repo)
156
+ : Promise.resolve({ ok: true, value: [] } as const),
157
+ shouldPushSlices
158
+ ? fetchRemoteSlices(repo)
159
+ : Promise.resolve({ ok: true, value: [] } as const),
160
+ ]);
161
+
162
+ if (!remoteTypesResult.ok) {
163
+ console.error(`Failed to fetch remote custom types: ${remoteTypesResult.error}`);
164
+ process.exitCode = 1;
165
+ return;
166
+ }
167
+
168
+ if (!remoteSlicesResult.ok) {
169
+ console.error(`Failed to fetch remote slices: ${remoteSlicesResult.error}`);
170
+ process.exitCode = 1;
171
+ return;
172
+ }
173
+
174
+ const remoteTypes = remoteTypesResult.value;
175
+ const remoteSlices = remoteSlicesResult.value;
176
+
177
+ if (!json) {
178
+ if (shouldPushTypes) {
179
+ console.info(`Local custom types: ${localTypes.length}`);
180
+ console.info(`Remote custom types: ${remoteTypes.length}`);
181
+ }
182
+ if (shouldPushSlices) {
183
+ console.info(`Local slices: ${localSlices.length}`);
184
+ console.info(`Remote slices: ${remoteSlices.length}`);
185
+ }
186
+ }
187
+
188
+ // Compute diffs
189
+ const typesDiff = shouldPushTypes
190
+ ? computeDiff([...localTypes], [...remoteTypes])
191
+ : { toInsert: [], toUpdate: [], toDelete: [] };
192
+ const slicesDiff = shouldPushSlices
193
+ ? computeDiff([...localSlices], [...remoteSlices])
194
+ : { toInsert: [], toUpdate: [], toDelete: [] };
195
+
196
+ // If --delete is not specified, clear the toDelete arrays
197
+ if (!deleteRemote) {
198
+ typesDiff.toDelete = [];
199
+ slicesDiff.toDelete = [];
200
+ }
201
+
202
+ const totalChanges =
203
+ typesDiff.toInsert.length +
204
+ typesDiff.toUpdate.length +
205
+ typesDiff.toDelete.length +
206
+ slicesDiff.toInsert.length +
207
+ slicesDiff.toUpdate.length +
208
+ slicesDiff.toDelete.length;
209
+
210
+ if (totalChanges === 0) {
211
+ if (json) {
212
+ console.info(
213
+ stringify({
214
+ customTypes: { inserted: [], updated: [], deleted: [] },
215
+ slices: { inserted: [], updated: [], deleted: [] },
216
+ }),
217
+ );
218
+ } else {
219
+ console.info("\nNo changes to push.");
220
+ }
221
+ return;
222
+ }
223
+
224
+ // Dry run - show what would happen
225
+ if (dryRun) {
226
+ if (json) {
227
+ console.info(
228
+ stringify({
229
+ customTypes: {
230
+ toInsert: typesDiff.toInsert.map((t) => t.id),
231
+ toUpdate: typesDiff.toUpdate.map((t) => t.id),
232
+ toDelete: typesDiff.toDelete,
233
+ },
234
+ slices: {
235
+ toInsert: slicesDiff.toInsert.map((s) => s.id),
236
+ toUpdate: slicesDiff.toUpdate.map((s) => s.id),
237
+ toDelete: slicesDiff.toDelete,
238
+ },
239
+ }),
240
+ );
241
+ } else {
242
+ console.info("");
243
+ if (shouldPushTypes) {
244
+ if (typesDiff.toInsert.length > 0) {
245
+ console.info("Would insert custom types:");
246
+ for (const ct of typesDiff.toInsert) {
247
+ console.info(` + ${ct.id}`);
248
+ }
249
+ }
250
+ if (typesDiff.toUpdate.length > 0) {
251
+ console.info("Would update custom types:");
252
+ for (const ct of typesDiff.toUpdate) {
253
+ console.info(` ~ ${ct.id}`);
254
+ }
255
+ }
256
+ if (typesDiff.toDelete.length > 0) {
257
+ console.info("Would delete custom types:");
258
+ for (const id of typesDiff.toDelete) {
259
+ console.info(` - ${id}`);
260
+ }
261
+ }
262
+ }
263
+ if (shouldPushSlices) {
264
+ if (slicesDiff.toInsert.length > 0) {
265
+ console.info("Would insert slices:");
266
+ for (const slice of slicesDiff.toInsert) {
267
+ console.info(` + ${slice.id}`);
268
+ }
269
+ }
270
+ if (slicesDiff.toUpdate.length > 0) {
271
+ console.info("Would update slices:");
272
+ for (const slice of slicesDiff.toUpdate) {
273
+ console.info(` ~ ${slice.id}`);
274
+ }
275
+ }
276
+ if (slicesDiff.toDelete.length > 0) {
277
+ console.info("Would delete slices:");
278
+ for (const id of slicesDiff.toDelete) {
279
+ console.info(` - ${id}`);
280
+ }
281
+ }
282
+ }
283
+ console.info(`\nDry run complete: ${totalChanges} changes would be made`);
284
+ }
285
+ return;
286
+ }
287
+
288
+ // Execute changes
289
+ const results = {
290
+ customTypes: { inserted: [] as string[], updated: [] as string[], deleted: [] as string[] },
291
+ slices: { inserted: [] as string[], updated: [] as string[], deleted: [] as string[] },
292
+ };
293
+
294
+ // Push custom types
295
+ if (shouldPushTypes) {
296
+ if (
297
+ !json &&
298
+ (typesDiff.toInsert.length > 0 ||
299
+ typesDiff.toUpdate.length > 0 ||
300
+ typesDiff.toDelete.length > 0)
301
+ ) {
302
+ console.info("\nPushing custom types:");
303
+ }
304
+
305
+ for (const ct of typesDiff.toInsert) {
306
+ const result = await insertCustomType(repo, ct as CustomType);
307
+ if (!result.ok) {
308
+ console.error(`Failed to insert custom type ${ct.id}: ${result.error}`);
309
+ process.exitCode = 1;
310
+ return;
311
+ }
312
+ results.customTypes.inserted.push(ct.id);
313
+ if (!json) {
314
+ console.info(` + ${ct.id}`);
315
+ }
316
+ }
317
+
318
+ for (const ct of typesDiff.toUpdate) {
319
+ const result = await updateCustomType(repo, ct as CustomType);
320
+ if (!result.ok) {
321
+ console.error(`Failed to update custom type ${ct.id}: ${result.error}`);
322
+ process.exitCode = 1;
323
+ return;
324
+ }
325
+ results.customTypes.updated.push(ct.id);
326
+ if (!json) {
327
+ console.info(` ~ ${ct.id}`);
328
+ }
329
+ }
330
+
331
+ for (const id of typesDiff.toDelete) {
332
+ const result = await deleteCustomType(repo, id);
333
+ if (!result.ok) {
334
+ console.error(`Failed to delete custom type ${id}: ${result.error}`);
335
+ process.exitCode = 1;
336
+ return;
337
+ }
338
+ results.customTypes.deleted.push(id);
339
+ if (!json) {
340
+ console.info(` - ${id}`);
341
+ }
342
+ }
343
+ }
344
+
345
+ // Push slices
346
+ if (shouldPushSlices) {
347
+ if (
348
+ !json &&
349
+ (slicesDiff.toInsert.length > 0 ||
350
+ slicesDiff.toUpdate.length > 0 ||
351
+ slicesDiff.toDelete.length > 0)
352
+ ) {
353
+ console.info("\nPushing slices:");
354
+ }
355
+
356
+ for (const slice of slicesDiff.toInsert) {
357
+ const result = await insertSlice(repo, slice as SharedSlice);
358
+ if (!result.ok) {
359
+ console.error(`Failed to insert slice ${slice.id}: ${result.error}`);
360
+ process.exitCode = 1;
361
+ return;
362
+ }
363
+ results.slices.inserted.push(slice.id);
364
+ if (!json) {
365
+ console.info(` + ${slice.id}`);
366
+ }
367
+ }
368
+
369
+ for (const slice of slicesDiff.toUpdate) {
370
+ const result = await updateSlice(repo, slice as SharedSlice);
371
+ if (!result.ok) {
372
+ console.error(`Failed to update slice ${slice.id}: ${result.error}`);
373
+ process.exitCode = 1;
374
+ return;
375
+ }
376
+ results.slices.updated.push(slice.id);
377
+ if (!json) {
378
+ console.info(` ~ ${slice.id}`);
379
+ }
380
+ }
381
+
382
+ for (const id of slicesDiff.toDelete) {
383
+ const result = await deleteSlice(repo, id);
384
+ if (!result.ok) {
385
+ console.error(`Failed to delete slice ${id}: ${result.error}`);
386
+ process.exitCode = 1;
387
+ return;
388
+ }
389
+ results.slices.deleted.push(id);
390
+ if (!json) {
391
+ console.info(` - ${id}`);
392
+ }
393
+ }
394
+ }
395
+
396
+ // Output summary
397
+ if (json) {
398
+ console.info(stringify(results));
399
+ } else {
400
+ const totalPushed =
401
+ results.customTypes.inserted.length +
402
+ results.customTypes.updated.length +
403
+ results.customTypes.deleted.length +
404
+ results.slices.inserted.length +
405
+ results.slices.updated.length +
406
+ results.slices.deleted.length;
407
+ console.info(`\nPush complete: ${totalPushed} changes`);
408
+ }
409
+ }