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.
- package/LICENSE +202 -0
- package/README.md +69 -0
- package/dist/builders-hKD4IrLX-DsO7BUQw.mjs +97 -0
- package/dist/dist-B11B2hHn.mjs +1 -0
- package/dist/dist-DT8CtumB.mjs +1 -0
- package/dist/framework-CfjEoVk0.mjs +17 -0
- package/dist/index.mjs +2537 -0
- package/dist/nextjs-9z7YrSnS.mjs +312 -0
- package/dist/nuxt-KoJ61G2q.mjs +59 -0
- package/dist/sveltekit-DjXKCG78.mjs +226 -0
- package/package.json +58 -0
- package/src/codegen-types.ts +82 -0
- package/src/codegen.ts +45 -0
- package/src/custom-type-add-field-boolean.ts +185 -0
- package/src/custom-type-add-field-color.ts +168 -0
- package/src/custom-type-add-field-date.ts +171 -0
- package/src/custom-type-add-field-embed.ts +168 -0
- package/src/custom-type-add-field-geo-point.ts +165 -0
- package/src/custom-type-add-field-group.ts +142 -0
- package/src/custom-type-add-field-image.ts +168 -0
- package/src/custom-type-add-field-key-text.ts +168 -0
- package/src/custom-type-add-field-link.ts +191 -0
- package/src/custom-type-add-field-number.ts +200 -0
- package/src/custom-type-add-field-rich-text.ts +192 -0
- package/src/custom-type-add-field-select.ts +174 -0
- package/src/custom-type-add-field-timestamp.ts +171 -0
- package/src/custom-type-add-field-uid.ts +151 -0
- package/src/custom-type-add-field.ts +116 -0
- package/src/custom-type-connect-slice.ts +178 -0
- package/src/custom-type-create.ts +98 -0
- package/src/custom-type-disconnect-slice.ts +134 -0
- package/src/custom-type-list.ts +110 -0
- package/src/custom-type-remove-field.ts +135 -0
- package/src/custom-type-remove.ts +103 -0
- package/src/custom-type-set-name.ts +102 -0
- package/src/custom-type-view.ts +118 -0
- package/src/custom-type.ts +85 -0
- package/src/docs-fetch.ts +146 -0
- package/src/docs-list.ts +131 -0
- package/src/docs.ts +54 -0
- package/src/env.d.ts +12 -0
- package/src/framework/index.ts +399 -0
- package/src/framework/nextjs.templates.ts +426 -0
- package/src/framework/nextjs.ts +216 -0
- package/src/framework/nuxt.templates.ts +74 -0
- package/src/framework/nuxt.ts +250 -0
- package/src/framework/sveltekit.templates.ts +278 -0
- package/src/framework/sveltekit.ts +241 -0
- package/src/index.ts +155 -0
- package/src/init.ts +173 -0
- package/src/lib/auth.ts +200 -0
- package/src/lib/browser.ts +11 -0
- package/src/lib/config.ts +111 -0
- package/src/lib/custom-types-api.ts +385 -0
- package/src/lib/field-path.ts +81 -0
- package/src/lib/file.ts +49 -0
- package/src/lib/json.ts +3 -0
- package/src/lib/packageJson.ts +35 -0
- package/src/lib/profile.ts +39 -0
- package/src/lib/request.ts +116 -0
- package/src/lib/segment.ts +145 -0
- package/src/lib/sentry.ts +63 -0
- package/src/lib/string.ts +10 -0
- package/src/lib/url.ts +31 -0
- package/src/locale-add.ts +116 -0
- package/src/locale-list.ts +107 -0
- package/src/locale-remove.ts +88 -0
- package/src/locale-set-default.ts +131 -0
- package/src/locale.ts +60 -0
- package/src/login.ts +45 -0
- package/src/logout.ts +36 -0
- package/src/page-type-add-field-boolean.ts +179 -0
- package/src/page-type-add-field-color.ts +165 -0
- package/src/page-type-add-field-date.ts +168 -0
- package/src/page-type-add-field-embed.ts +165 -0
- package/src/page-type-add-field-geo-point.ts +162 -0
- package/src/page-type-add-field-group.ts +139 -0
- package/src/page-type-add-field-image.ts +165 -0
- package/src/page-type-add-field-key-text.ts +165 -0
- package/src/page-type-add-field-link.ts +188 -0
- package/src/page-type-add-field-number.ts +197 -0
- package/src/page-type-add-field-rich-text.ts +189 -0
- package/src/page-type-add-field-select.ts +171 -0
- package/src/page-type-add-field-timestamp.ts +168 -0
- package/src/page-type-add-field-uid.ts +148 -0
- package/src/page-type-add-field.ts +116 -0
- package/src/page-type-connect-slice.ts +178 -0
- package/src/page-type-create.ts +128 -0
- package/src/page-type-disconnect-slice.ts +134 -0
- package/src/page-type-list.ts +109 -0
- package/src/page-type-remove-field.ts +135 -0
- package/src/page-type-remove.ts +103 -0
- package/src/page-type-set-name.ts +102 -0
- package/src/page-type-set-repeatable.ts +111 -0
- package/src/page-type-view.ts +118 -0
- package/src/page-type.ts +90 -0
- package/src/preview-add.ts +126 -0
- package/src/preview-get-simulator.ts +104 -0
- package/src/preview-list.ts +106 -0
- package/src/preview-remove-simulator.ts +80 -0
- package/src/preview-remove.ts +109 -0
- package/src/preview-set-name.ts +137 -0
- package/src/preview-set-simulator.ts +116 -0
- package/src/preview.ts +75 -0
- package/src/pull.ts +236 -0
- package/src/push.ts +409 -0
- package/src/repo-create.ts +175 -0
- package/src/repo-get-access.ts +86 -0
- package/src/repo-list.ts +100 -0
- package/src/repo-set-access.ts +100 -0
- package/src/repo-set-name.ts +102 -0
- package/src/repo-view.ts +113 -0
- package/src/repo.ts +70 -0
- package/src/slice-add-field-boolean.ts +219 -0
- package/src/slice-add-field-color.ts +205 -0
- package/src/slice-add-field-date.ts +205 -0
- package/src/slice-add-field-embed.ts +205 -0
- package/src/slice-add-field-geo-point.ts +202 -0
- package/src/slice-add-field-group.ts +170 -0
- package/src/slice-add-field-image.ts +202 -0
- package/src/slice-add-field-key-text.ts +205 -0
- package/src/slice-add-field-link.ts +224 -0
- package/src/slice-add-field-number.ts +205 -0
- package/src/slice-add-field-rich-text.ts +229 -0
- package/src/slice-add-field-select.ts +211 -0
- package/src/slice-add-field-timestamp.ts +205 -0
- package/src/slice-add-field.ts +111 -0
- package/src/slice-add-variation.ts +142 -0
- package/src/slice-create.ts +164 -0
- package/src/slice-list-variations.ts +71 -0
- package/src/slice-list.ts +60 -0
- package/src/slice-remove-field.ts +125 -0
- package/src/slice-remove-variation.ts +113 -0
- package/src/slice-remove.ts +92 -0
- package/src/slice-rename.ts +104 -0
- package/src/slice-set-screenshot.ts +239 -0
- package/src/slice-view.ts +83 -0
- package/src/slice.ts +95 -0
- package/src/status.ts +834 -0
- package/src/sync.ts +259 -0
- package/src/token-create.ts +203 -0
- package/src/token-delete.ts +182 -0
- package/src/token-list.ts +223 -0
- package/src/token-set-name.ts +193 -0
- package/src/token.ts +60 -0
- package/src/webhook-add-header.ts +118 -0
- package/src/webhook-create.ts +152 -0
- package/src/webhook-disable.ts +109 -0
- package/src/webhook-enable.ts +132 -0
- package/src/webhook-list.ts +93 -0
- package/src/webhook-remove-header.ts +117 -0
- package/src/webhook-remove.ts +106 -0
- package/src/webhook-set-triggers.ts +148 -0
- package/src/webhook-status.ts +90 -0
- package/src/webhook-test.ts +106 -0
- package/src/webhook-view.ts +147 -0
- package/src/webhook.ts +95 -0
- 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
|
+
}
|