canopycms 0.0.16 → 0.0.18
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/README.md +120 -34
- package/dist/ai/generate.js +3 -3
- package/dist/ai/handler.js +5 -5
- package/dist/ai/index.js +3 -3
- package/dist/ai/json-to-markdown.js +1 -1
- package/dist/ai/json-to-markdown.js.map +1 -1
- package/dist/ai/resolve-branch.js +2 -2
- package/dist/api/__test__/mock-client.js +1 -1
- package/dist/api/assets.js +1 -1
- package/dist/api/branch-merge.js +3 -3
- package/dist/api/branch-review.js +4 -4
- package/dist/api/branch-status.js +8 -8
- package/dist/api/branch-withdraw.js +5 -5
- package/dist/api/branch.js +9 -9
- package/dist/api/comments.js +4 -4
- package/dist/api/content.d.ts.map +1 -1
- package/dist/api/content.js +17 -16
- package/dist/api/content.js.map +1 -1
- package/dist/api/entries.js +8 -8
- package/dist/api/github-sync.js +3 -3
- package/dist/api/groups.js +4 -4
- package/dist/api/guards.js +1 -1
- package/dist/api/index.js +3 -3
- package/dist/api/permissions.js +4 -4
- package/dist/api/reference-options.js +5 -5
- package/dist/api/resolve-references.js +4 -4
- package/dist/api/route-builder.js +1 -1
- package/dist/api/schema.js +5 -5
- package/dist/api/settings-helpers.js +1 -1
- package/dist/api/user.js +1 -1
- package/dist/api/validators.js +3 -3
- package/dist/asset-store.js +1 -1
- package/dist/auth/cache.js +2 -2
- package/dist/auth/caching-auth-plugin.js +1 -1
- package/dist/auth/file-based-auth-cache.js +1 -1
- package/dist/auth/index.js +1 -1
- package/dist/authorization/branch.js +1 -1
- package/dist/authorization/content.js +3 -3
- package/dist/authorization/groups/index.js +2 -2
- package/dist/authorization/groups/loader.js +4 -4
- package/dist/authorization/index.js +8 -8
- package/dist/authorization/path.js +1 -1
- package/dist/authorization/permissions/index.js +2 -2
- package/dist/authorization/permissions/loader.js +3 -3
- package/dist/authorization/permissions/schema.js +1 -1
- package/dist/authorization/test-utils.js +1 -1
- package/dist/authorization/validation.js +1 -1
- package/dist/branch-metadata.js +3 -3
- package/dist/branch-registry.js +2 -2
- package/dist/branch-schema-cache.js +2 -2
- package/dist/branch-workspace.js +6 -6
- package/dist/build/generate-ai-content.js +4 -4
- package/dist/build/index.js +1 -1
- package/dist/cli/cli.js +5 -5
- package/dist/cli/generate-ai-content.js +40 -29
- package/dist/cli/init.d.ts +5 -0
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +68 -25
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/sync.js +1 -1
- package/dist/cli/template-files/canopy.ts.template +10 -6
- package/dist/cli/template-files/edit-page-dev.tsx.template +16 -0
- package/dist/cli/template-files/edit-page.tsx.template +14 -21
- package/dist/cli/template-files/middleware-clerk.ts.template +13 -0
- package/dist/cli/template-files/middleware.ts.template +30 -0
- package/dist/cli/template-files/next.config-static.ts.template +13 -0
- package/dist/cli/template-files/next.config.ts.template +5 -0
- package/dist/cli/template-files/schemas.ts.template +4 -2
- package/dist/cli/templates.d.ts +8 -0
- package/dist/cli/templates.d.ts.map +1 -1
- package/dist/cli/templates.js +22 -2
- package/dist/cli/templates.js.map +1 -1
- package/dist/client.js +9 -9
- package/dist/config/flatten.js +2 -2
- package/dist/config/helpers.js +3 -3
- package/dist/config/index.js +9 -9
- package/dist/config/schemas/collection.js +1 -1
- package/dist/config/schemas/config.js +2 -2
- package/dist/config/schemas/field.d.ts +21 -0
- package/dist/config/schemas/field.d.ts.map +1 -1
- package/dist/config/schemas/field.js +2 -1
- package/dist/config/schemas/field.js.map +1 -1
- package/dist/config/types.d.ts +7 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/validation.js +2 -2
- package/dist/config-test.js +2 -2
- package/dist/config.js +2 -2
- package/dist/content-id-index.js +2 -2
- package/dist/content-listing.d.ts +3 -2
- package/dist/content-listing.d.ts.map +1 -1
- package/dist/content-listing.js +15 -12
- package/dist/content-listing.js.map +1 -1
- package/dist/content-reader.d.ts.map +1 -1
- package/dist/content-reader.js +18 -14
- package/dist/content-reader.js.map +1 -1
- package/dist/content-store.d.ts +5 -0
- package/dist/content-store.d.ts.map +1 -1
- package/dist/content-store.js +34 -24
- package/dist/content-store.js.map +1 -1
- package/dist/content-tree.d.ts.map +1 -1
- package/dist/content-tree.js +8 -3
- package/dist/content-tree.js.map +1 -1
- package/dist/context.d.ts +38 -7
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +38 -6
- package/dist/context.js.map +1 -1
- package/dist/editor/BranchManager.js +4 -4
- package/dist/editor/CanopyEditor.js +3 -3
- package/dist/editor/CanopyEditorPage.js +1 -1
- package/dist/editor/CommentsPanel.js +1 -1
- package/dist/editor/Editor.js +18 -18
- package/dist/editor/EntryNavigator.js +1 -1
- package/dist/editor/FormRenderer.js +12 -12
- package/dist/editor/GroupManager.js +1 -1
- package/dist/editor/PermissionManager.js +1 -1
- package/dist/editor/client-reference-resolver.js +1 -1
- package/dist/editor/comments/BranchComments.js +1 -1
- package/dist/editor/comments/EntryComments.js +1 -1
- package/dist/editor/comments/FieldWrapper.js +1 -1
- package/dist/editor/comments/InlineCommentThread.js +1 -1
- package/dist/editor/comments/ThreadCarousel.js +1 -1
- package/dist/editor/components/EditorHeader.js +1 -1
- package/dist/editor/components/UserBadge.js +1 -1
- package/dist/editor/components/index.js +3 -3
- package/dist/editor/context/ApiClientContext.js +1 -1
- package/dist/editor/context/index.js +2 -2
- package/dist/editor/editor-config.js +2 -2
- package/dist/editor/editor-config.js.map +1 -1
- package/dist/editor/editor-utils.js +1 -1
- package/dist/editor/fields/BlockField.js +1 -1
- package/dist/editor/fields/ObjectField.js +1 -1
- package/dist/editor/fields/ReferenceField.js +1 -1
- package/dist/editor/group-manager/GroupCard.js +1 -1
- package/dist/editor/group-manager/InternalGroupsTab.js +1 -1
- package/dist/editor/group-manager/MemberList.js +1 -1
- package/dist/editor/group-manager/index.js +9 -9
- package/dist/editor/hooks/__test__/test-utils.js +3 -3
- package/dist/editor/hooks/index.js +11 -11
- package/dist/editor/hooks/useBranchActions.js +1 -1
- package/dist/editor/hooks/useBranchManager.js +1 -1
- package/dist/editor/hooks/useCommentSystem.js +2 -2
- package/dist/editor/hooks/useDraftManager.js +1 -1
- package/dist/editor/hooks/useEntryManager.js +3 -3
- package/dist/editor/hooks/useGroupManager.js +1 -1
- package/dist/editor/hooks/usePermissionManager.js +1 -1
- package/dist/editor/hooks/useReferenceResolution.js +1 -1
- package/dist/editor/hooks/useSchemaManager.js +1 -1
- package/dist/editor/hooks/useUserContext.js +1 -1
- package/dist/editor/permission-manager/PermissionEditor.js +4 -4
- package/dist/editor/permission-manager/PermissionLevelBadge.js +1 -1
- package/dist/editor/permission-manager/PermissionTree.js +3 -3
- package/dist/editor/permission-manager/UserSelector.js +1 -1
- package/dist/editor/permission-manager/hooks/usePermissionTree.js +2 -2
- package/dist/editor/permission-manager/index.js +6 -6
- package/dist/editor/preview-bridge.js +1 -1
- package/dist/editor/schema-editor/CollectionEditor.js +2 -2
- package/dist/editor/schema-editor/index.js +2 -2
- package/dist/entry-schema-registry.d.ts.map +1 -1
- package/dist/entry-schema-registry.js +12 -3
- package/dist/entry-schema-registry.js.map +1 -1
- package/dist/entry-schema.d.ts +1 -0
- package/dist/entry-schema.d.ts.map +1 -1
- package/dist/entry-schema.js.map +1 -1
- package/dist/git-manager.js +4 -4
- package/dist/github-service.d.ts.map +1 -1
- package/dist/github-service.js +12 -8
- package/dist/github-service.js.map +1 -1
- package/dist/http/handler.js +7 -7
- package/dist/http/index.js +3 -3
- package/dist/http/router.js +12 -12
- package/dist/id.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -6
- package/dist/index.js.map +1 -1
- package/dist/operating-mode/client-unsafe-strategy.js +2 -2
- package/dist/operating-mode/client.js +1 -1
- package/dist/operating-mode/index.js +2 -2
- package/dist/paths/branch.js +1 -1
- package/dist/paths/index.d.ts +1 -1
- package/dist/paths/index.d.ts.map +1 -1
- package/dist/paths/index.js +6 -6
- package/dist/paths/index.js.map +1 -1
- package/dist/paths/normalize.d.ts +8 -0
- package/dist/paths/normalize.d.ts.map +1 -1
- package/dist/paths/normalize.js +17 -0
- package/dist/paths/normalize.js.map +1 -1
- package/dist/paths/test-utils.js +1 -1
- package/dist/paths/validation.js +1 -1
- package/dist/reference-resolver.js +1 -1
- package/dist/schema/index.js +2 -2
- package/dist/schema/meta-loader.js +1 -1
- package/dist/schema/resolver.js +1 -1
- package/dist/schema/schema-store.js +4 -4
- package/dist/server.js +13 -13
- package/dist/services.js +12 -12
- package/dist/settings-branch-utils.js +1 -1
- package/dist/settings-workspace.js +3 -3
- package/dist/task-queue/index.js +1 -1
- package/dist/task-queue/task-queue.js +1 -1
- package/dist/url-path-resolver.d.ts +16 -0
- package/dist/url-path-resolver.d.ts.map +1 -0
- package/dist/url-path-resolver.js +31 -0
- package/dist/url-path-resolver.js.map +1 -0
- package/dist/user.js +1 -1
- package/dist/utils/body-field.d.ts +18 -0
- package/dist/utils/body-field.d.ts.map +1 -0
- package/dist/utils/body-field.js +39 -0
- package/dist/utils/body-field.js.map +1 -0
- package/dist/utils/fs.js +1 -1
- package/dist/utils/sanitize-href.d.ts +19 -0
- package/dist/utils/sanitize-href.d.ts.map +1 -0
- package/dist/utils/sanitize-href.js +30 -0
- package/dist/utils/sanitize-href.js.map +1 -0
- package/dist/validation/reference-validator.js +2 -2
- package/dist/worker/cms-worker.js +5 -5
- package/dist/worker/task-queue-config.js +1 -1
- package/dist/worker/task-queue.js +2 -2
- package/package.json +1 -1
|
@@ -162,7 +162,8 @@ var init_field = __esm({
|
|
|
162
162
|
description: z.string().optional(),
|
|
163
163
|
required: z.boolean().optional(),
|
|
164
164
|
list: z.boolean().optional(),
|
|
165
|
-
isTitle: z.boolean().optional()
|
|
165
|
+
isTitle: z.boolean().optional(),
|
|
166
|
+
isBody: z.boolean().optional()
|
|
166
167
|
});
|
|
167
168
|
selectOptionSchema = z.union([
|
|
168
169
|
z.string(),
|
|
@@ -516,14 +517,6 @@ var init_config2 = __esm({
|
|
|
516
517
|
}
|
|
517
518
|
});
|
|
518
519
|
|
|
519
|
-
// dist/config.js
|
|
520
|
-
var init_config3 = __esm({
|
|
521
|
-
"dist/config.js"() {
|
|
522
|
-
"use strict";
|
|
523
|
-
init_config2();
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
-
|
|
527
520
|
// dist/operating-mode/client-unsafe-strategy.js
|
|
528
521
|
import path3 from "node:path";
|
|
529
522
|
function operatingStrategy(mode) {
|
|
@@ -554,7 +547,7 @@ var init_client_unsafe_strategy = __esm({
|
|
|
554
547
|
"dist/operating-mode/client-unsafe-strategy.js"() {
|
|
555
548
|
"use strict";
|
|
556
549
|
init_client_safe_strategy();
|
|
557
|
-
|
|
550
|
+
init_config2();
|
|
558
551
|
ProdStrategy = class extends ProdClientSafeStrategy {
|
|
559
552
|
// All client-safe methods inherited automatically from ProdClientSafeStrategy:
|
|
560
553
|
// - mode, supportsBranching(), supportsStatusBadge(), supportsComments()
|
|
@@ -715,6 +708,15 @@ async function atomicWriteFile(filePath, content) {
|
|
|
715
708
|
}
|
|
716
709
|
}
|
|
717
710
|
|
|
711
|
+
// dist/utils/body-field.js
|
|
712
|
+
function findBodyFieldName(fields) {
|
|
713
|
+
for (const field of fields) {
|
|
714
|
+
if ("isBody" in field && field.isBody)
|
|
715
|
+
return field.name;
|
|
716
|
+
}
|
|
717
|
+
return "body";
|
|
718
|
+
}
|
|
719
|
+
|
|
718
720
|
// dist/content-id-index.js
|
|
719
721
|
import fs2 from "node:fs/promises";
|
|
720
722
|
import path2 from "node:path";
|
|
@@ -1091,6 +1093,10 @@ async function ensureBranchRoot(options) {
|
|
|
1091
1093
|
|
|
1092
1094
|
// dist/content-store.js
|
|
1093
1095
|
var ContentStoreError = class extends Error {
|
|
1096
|
+
constructor(message, code) {
|
|
1097
|
+
super(message);
|
|
1098
|
+
this.code = code;
|
|
1099
|
+
}
|
|
1094
1100
|
};
|
|
1095
1101
|
function getDefaultEntryType(entries) {
|
|
1096
1102
|
if (!entries || entries.length === 0)
|
|
@@ -1099,10 +1105,10 @@ function getDefaultEntryType(entries) {
|
|
|
1099
1105
|
}
|
|
1100
1106
|
function validateSlug(slug) {
|
|
1101
1107
|
if (slug.includes("/")) {
|
|
1102
|
-
throw new ContentStoreError("Slugs cannot contain forward slashes. Use nested collections instead.");
|
|
1108
|
+
throw new ContentStoreError("Slugs cannot contain forward slashes. Use nested collections instead.", "VALIDATION");
|
|
1103
1109
|
}
|
|
1104
1110
|
if (slug.includes("\\")) {
|
|
1105
|
-
throw new ContentStoreError("Slugs cannot contain backslashes. Use nested collections instead.");
|
|
1111
|
+
throw new ContentStoreError("Slugs cannot contain backslashes. Use nested collections instead.", "VALIDATION");
|
|
1106
1112
|
}
|
|
1107
1113
|
}
|
|
1108
1114
|
var ContentStore = class {
|
|
@@ -1134,14 +1140,14 @@ var ContentStore = class {
|
|
|
1134
1140
|
const normalized = normalizeFilesystemPath(path13);
|
|
1135
1141
|
const item = this.schemaIndex.get(normalized);
|
|
1136
1142
|
if (!item) {
|
|
1137
|
-
throw new ContentStoreError(`Unknown schema item: ${path13}
|
|
1143
|
+
throw new ContentStoreError(`Unknown schema item: ${path13}`, "NO_SCHEMA_ITEM");
|
|
1138
1144
|
}
|
|
1139
1145
|
return item;
|
|
1140
1146
|
}
|
|
1141
1147
|
assertCollection(collectionPath) {
|
|
1142
1148
|
const item = this.assertSchemaItem(collectionPath);
|
|
1143
1149
|
if (item.type !== "collection") {
|
|
1144
|
-
throw new ContentStoreError(`Path is not a collection: ${collectionPath}
|
|
1150
|
+
throw new ContentStoreError(`Path is not a collection: ${collectionPath}`, "NO_SCHEMA_ITEM");
|
|
1145
1151
|
}
|
|
1146
1152
|
return item;
|
|
1147
1153
|
}
|
|
@@ -1166,7 +1172,7 @@ var ContentStore = class {
|
|
|
1166
1172
|
const parentPath = schemaItem.parentPath || "";
|
|
1167
1173
|
const parentCollection = this.schemaIndex.get(parentPath);
|
|
1168
1174
|
if (!parentCollection || parentCollection.type !== "collection") {
|
|
1169
|
-
throw new ContentStoreError(`Parent collection not found for entry type: ${schemaItem.name}
|
|
1175
|
+
throw new ContentStoreError(`Parent collection not found for entry type: ${schemaItem.name}`, "NO_SCHEMA_ITEM");
|
|
1170
1176
|
}
|
|
1171
1177
|
const effectiveSlug = slug || schemaItem.name;
|
|
1172
1178
|
return this.buildPaths(parentCollection, effectiveSlug, {
|
|
@@ -1177,14 +1183,14 @@ var ContentStore = class {
|
|
|
1177
1183
|
if (schemaItem.type === "collection") {
|
|
1178
1184
|
const safeSlug = slug.replace(/^\/+/, "").toLowerCase();
|
|
1179
1185
|
if (!safeSlug) {
|
|
1180
|
-
throw new ContentStoreError("Slug is required for collection entries");
|
|
1186
|
+
throw new ContentStoreError("Slug is required for collection entries", "VALIDATION");
|
|
1181
1187
|
}
|
|
1182
1188
|
validateSlug(safeSlug);
|
|
1183
1189
|
let entryTypeConfig;
|
|
1184
1190
|
if (options.entryTypeName) {
|
|
1185
1191
|
entryTypeConfig = schemaItem.entries?.find((e) => e.name === options.entryTypeName);
|
|
1186
1192
|
if (!entryTypeConfig) {
|
|
1187
|
-
throw new ContentStoreError(`Entry type '${options.entryTypeName}' not found in collection
|
|
1193
|
+
throw new ContentStoreError(`Entry type '${options.entryTypeName}' not found in collection`, "NO_SCHEMA_ITEM");
|
|
1188
1194
|
}
|
|
1189
1195
|
} else {
|
|
1190
1196
|
entryTypeConfig = getDefaultEntryType(schemaItem.entries);
|
|
@@ -1197,7 +1203,7 @@ var ContentStore = class {
|
|
|
1197
1203
|
collectionRoot = path5.resolve(this.root, schemaItem.logicalPath);
|
|
1198
1204
|
}
|
|
1199
1205
|
if (!collectionRoot.startsWith(rootWithSep)) {
|
|
1200
|
-
throw new ContentStoreError("Path traversal detected");
|
|
1206
|
+
throw new ContentStoreError("Path traversal detected", "VALIDATION");
|
|
1201
1207
|
}
|
|
1202
1208
|
let id = options.existingId;
|
|
1203
1209
|
let existingFilename;
|
|
@@ -1230,7 +1236,7 @@ var ContentStore = class {
|
|
|
1230
1236
|
const resolved = path5.resolve(collectionRoot, filename);
|
|
1231
1237
|
const collectionRootWithSep = collectionRoot.endsWith(path5.sep) ? collectionRoot : `${collectionRoot}${path5.sep}`;
|
|
1232
1238
|
if (!resolved.startsWith(collectionRootWithSep)) {
|
|
1233
|
-
throw new ContentStoreError("Path traversal detected");
|
|
1239
|
+
throw new ContentStoreError("Path traversal detected", "VALIDATION");
|
|
1234
1240
|
}
|
|
1235
1241
|
return {
|
|
1236
1242
|
absolutePath: resolved,
|
|
@@ -1238,7 +1244,7 @@ var ContentStore = class {
|
|
|
1238
1244
|
id
|
|
1239
1245
|
};
|
|
1240
1246
|
}
|
|
1241
|
-
throw new ContentStoreError("Invalid schema item type");
|
|
1247
|
+
throw new ContentStoreError("Invalid schema item type", "VALIDATION");
|
|
1242
1248
|
}
|
|
1243
1249
|
/**
|
|
1244
1250
|
* Path resolution: resolves a URL path to a schema item
|
|
@@ -1246,7 +1252,7 @@ var ContentStore = class {
|
|
|
1246
1252
|
*/
|
|
1247
1253
|
resolvePath(pathSegments) {
|
|
1248
1254
|
if (pathSegments.length === 0) {
|
|
1249
|
-
throw new ContentStoreError("Empty path");
|
|
1255
|
+
throw new ContentStoreError("Empty path", "VALIDATION");
|
|
1250
1256
|
}
|
|
1251
1257
|
const logicalPath = pathSegments.join("/");
|
|
1252
1258
|
const slug = pathSegments[pathSegments.length - 1].toLowerCase();
|
|
@@ -1259,7 +1265,7 @@ var ContentStore = class {
|
|
|
1259
1265
|
slug
|
|
1260
1266
|
};
|
|
1261
1267
|
}
|
|
1262
|
-
throw new ContentStoreError(`No schema item found for path: ${logicalPath}
|
|
1268
|
+
throw new ContentStoreError(`No schema item found for path: ${logicalPath}`, "NO_SCHEMA_ITEM");
|
|
1263
1269
|
}
|
|
1264
1270
|
async resolveDocumentPath(schemaPath, slug = "") {
|
|
1265
1271
|
const schemaItem = this.assertSchemaItem(schemaPath);
|
|
@@ -1298,6 +1304,7 @@ var ContentStore = class {
|
|
|
1298
1304
|
format,
|
|
1299
1305
|
data: parsed.data ?? {},
|
|
1300
1306
|
body: parsed.content,
|
|
1307
|
+
bodyFieldName: findBodyFieldName(fields),
|
|
1301
1308
|
relativePath,
|
|
1302
1309
|
absolutePath
|
|
1303
1310
|
};
|
|
@@ -1311,22 +1318,25 @@ var ContentStore = class {
|
|
|
1311
1318
|
const idIndex = await this.idIndex();
|
|
1312
1319
|
const schemaItem = this.assertSchemaItem(collectionPath);
|
|
1313
1320
|
let expectedFormat;
|
|
1321
|
+
let fields = [];
|
|
1314
1322
|
if (schemaItem.type === "entry-type") {
|
|
1315
1323
|
expectedFormat = schemaItem.format;
|
|
1324
|
+
fields = schemaItem.schema;
|
|
1316
1325
|
} else {
|
|
1317
1326
|
let entryTypeConfig;
|
|
1318
1327
|
if (entryTypeName) {
|
|
1319
1328
|
entryTypeConfig = schemaItem.entries?.find((e) => e.name === entryTypeName);
|
|
1320
1329
|
if (!entryTypeConfig) {
|
|
1321
|
-
throw new ContentStoreError(`Entry type '${entryTypeName}' not found in collection
|
|
1330
|
+
throw new ContentStoreError(`Entry type '${entryTypeName}' not found in collection`, "NO_SCHEMA_ITEM");
|
|
1322
1331
|
}
|
|
1323
1332
|
} else {
|
|
1324
1333
|
entryTypeConfig = getDefaultEntryType(schemaItem.entries);
|
|
1325
1334
|
}
|
|
1326
1335
|
expectedFormat = entryTypeConfig?.format || "json";
|
|
1336
|
+
fields = entryTypeConfig?.schema || [];
|
|
1327
1337
|
}
|
|
1328
1338
|
if (expectedFormat !== input.format) {
|
|
1329
|
-
throw new ContentStoreError(`Format mismatch: expects ${expectedFormat}, got ${input.format}
|
|
1339
|
+
throw new ContentStoreError(`Format mismatch: expects ${expectedFormat}, got ${input.format}`, "VALIDATION");
|
|
1330
1340
|
}
|
|
1331
1341
|
const { absolutePath, relativePath, id } = await this.buildPaths(schemaItem, slug, {
|
|
1332
1342
|
entryTypeName
|
|
@@ -1383,6 +1393,7 @@ var ContentStore = class {
|
|
|
1383
1393
|
format: input.format,
|
|
1384
1394
|
data: input.data ?? {},
|
|
1385
1395
|
body: input.body,
|
|
1396
|
+
bodyFieldName: findBodyFieldName(fields),
|
|
1386
1397
|
relativePath,
|
|
1387
1398
|
absolutePath
|
|
1388
1399
|
};
|
|
@@ -1436,13 +1447,13 @@ var ContentStore = class {
|
|
|
1436
1447
|
validateSlug(newSlug);
|
|
1437
1448
|
const safeNewSlug = newSlug.replace(/^\/+/, "");
|
|
1438
1449
|
if (!safeNewSlug) {
|
|
1439
|
-
throw new ContentStoreError("New slug cannot be empty");
|
|
1450
|
+
throw new ContentStoreError("New slug cannot be empty", "VALIDATION");
|
|
1440
1451
|
}
|
|
1441
1452
|
const { absolutePath: currentPath, relativePath: currentRelPath } = await this.buildPaths(collection, currentSlug);
|
|
1442
1453
|
try {
|
|
1443
1454
|
await fs4.access(currentPath);
|
|
1444
1455
|
} catch {
|
|
1445
|
-
throw new ContentStoreError(`Entry not found: ${currentSlug}
|
|
1456
|
+
throw new ContentStoreError(`Entry not found: ${currentSlug}`, "NOT_FOUND");
|
|
1446
1457
|
}
|
|
1447
1458
|
if (currentSlug === safeNewSlug) {
|
|
1448
1459
|
return { newPath: `${collectionPath}/${currentSlug}` };
|
|
@@ -1450,7 +1461,7 @@ var ContentStore = class {
|
|
|
1450
1461
|
const currentFilename = path5.basename(currentPath);
|
|
1451
1462
|
const parts = currentFilename.split(".");
|
|
1452
1463
|
if (parts.length < 4) {
|
|
1453
|
-
throw new ContentStoreError(`Invalid entry filename format: ${currentFilename}
|
|
1464
|
+
throw new ContentStoreError(`Invalid entry filename format: ${currentFilename}`, "VALIDATION");
|
|
1454
1465
|
}
|
|
1455
1466
|
const entryTypeName = parts[0];
|
|
1456
1467
|
const contentId = parts[parts.length - 2];
|
|
@@ -1465,7 +1476,7 @@ var ContentStore = class {
|
|
|
1465
1476
|
continue;
|
|
1466
1477
|
const existingSlug = extractSlugFromFilename(entry.name, entryTypeName);
|
|
1467
1478
|
if (existingSlug === safeNewSlug) {
|
|
1468
|
-
throw new ContentStoreError(`Entry with slug "${safeNewSlug}" already exists in collection "${collectionPath}"
|
|
1479
|
+
throw new ContentStoreError(`Entry with slug "${safeNewSlug}" already exists in collection "${collectionPath}"`, "VALIDATION");
|
|
1469
1480
|
}
|
|
1470
1481
|
}
|
|
1471
1482
|
} catch (err) {
|
|
@@ -2152,7 +2163,7 @@ function formatInlineValue(field, value) {
|
|
|
2152
2163
|
}
|
|
2153
2164
|
function yamlValue(value) {
|
|
2154
2165
|
if (/[:#{}[\],&*?|>!%@`]/.test(value) || value.includes("\n")) {
|
|
2155
|
-
return `"${value.replace(/"/g, '\\"')}"`;
|
|
2166
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
2156
2167
|
}
|
|
2157
2168
|
return value;
|
|
2158
2169
|
}
|
package/dist/cli/init.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AuthPlugin } from '../auth/plugin';
|
|
2
|
+
export type AuthProvider = 'clerk' | 'dev';
|
|
2
3
|
export interface InitOptions {
|
|
3
4
|
mode: 'dev';
|
|
4
5
|
appDir: string;
|
|
@@ -6,6 +7,10 @@ export interface InitOptions {
|
|
|
6
7
|
force: boolean;
|
|
7
8
|
nonInteractive: boolean;
|
|
8
9
|
ai: boolean;
|
|
10
|
+
/** Pre-set auth provider (skips prompt). */
|
|
11
|
+
authProvider?: AuthProvider;
|
|
12
|
+
/** Pre-set static build choice (skips prompt). */
|
|
13
|
+
staticBuild?: boolean;
|
|
9
14
|
}
|
|
10
15
|
interface InitDeployOptions {
|
|
11
16
|
cloud: 'aws';
|
package/dist/cli/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAGhD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,KAAK,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,OAAO,CAAA;IACd,cAAc,EAAE,OAAO,CAAA;IACvB,EAAE,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAGhD,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,CAAA;AAE1C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,KAAK,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,OAAO,CAAA;IACd,cAAc,EAAE,OAAO,CAAA;IACvB,EAAE,EAAE,OAAO,CAAA;IACX,4CAA4C;IAC5C,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,kDAAkD;IAClD,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,UAAU,iBAAiB;IACzB,KAAK,EAAE,KAAK,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,OAAO,CAAA;IACd,cAAc,EAAE,OAAO,CAAA;CACxB;AA+CD;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqI9D;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2C7E;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiEhB"}
|
package/dist/cli/init.js
CHANGED
|
@@ -48,7 +48,8 @@ var init_field = __esm({
|
|
|
48
48
|
description: z.string().optional(),
|
|
49
49
|
required: z.boolean().optional(),
|
|
50
50
|
list: z.boolean().optional(),
|
|
51
|
-
isTitle: z.boolean().optional()
|
|
51
|
+
isTitle: z.boolean().optional(),
|
|
52
|
+
isBody: z.boolean().optional()
|
|
52
53
|
});
|
|
53
54
|
selectOptionSchema = z.union([
|
|
54
55
|
z.string(),
|
|
@@ -314,14 +315,6 @@ var init_config2 = __esm({
|
|
|
314
315
|
}
|
|
315
316
|
});
|
|
316
317
|
|
|
317
|
-
// dist/config.js
|
|
318
|
-
var init_config3 = __esm({
|
|
319
|
-
"dist/config.js"() {
|
|
320
|
-
"use strict";
|
|
321
|
-
init_config2();
|
|
322
|
-
}
|
|
323
|
-
});
|
|
324
|
-
|
|
325
318
|
// dist/cli/templates.js
|
|
326
319
|
var templates_exports = {};
|
|
327
320
|
__export(templates_exports, {
|
|
@@ -333,6 +326,8 @@ __export(templates_exports, {
|
|
|
333
326
|
dockerfileCms: () => dockerfileCms,
|
|
334
327
|
editPage: () => editPage,
|
|
335
328
|
githubWorkflowCms: () => githubWorkflowCms,
|
|
329
|
+
middleware: () => middleware,
|
|
330
|
+
nextConfig: () => nextConfig,
|
|
336
331
|
schemasTemplate: () => schemasTemplate
|
|
337
332
|
});
|
|
338
333
|
import fs2 from "node:fs/promises";
|
|
@@ -347,7 +342,9 @@ async function canopyCmsConfig(options) {
|
|
|
347
342
|
}
|
|
348
343
|
async function canopyContext(options) {
|
|
349
344
|
const template = await readTemplate("canopy.ts.template");
|
|
350
|
-
|
|
345
|
+
const authImports = options.authProvider === "clerk" ? "import { createClerkAuthPlugin } from 'canopycms-auth-clerk'\nimport { createDevAuthPlugin } from 'canopycms-auth-dev'" : "import { createDevAuthPlugin } from 'canopycms-auth-dev'";
|
|
346
|
+
const authPlugin = options.authProvider === "clerk" ? "process.env.CANOPY_AUTH_MODE === 'clerk'\n ? createClerkAuthPlugin({ useOrganizationsAsGroups: true })\n : createDevAuthPlugin()" : "createDevAuthPlugin()";
|
|
347
|
+
return template.replace("{{AUTH_IMPORTS}}", authImports).replace("{{AUTH_PLUGIN}}", authPlugin).replace("{{CONFIG_IMPORT}}", options.configImport);
|
|
351
348
|
}
|
|
352
349
|
async function schemasTemplate() {
|
|
353
350
|
return readTemplate("schemas.ts.template");
|
|
@@ -357,7 +354,8 @@ async function apiRoute(options) {
|
|
|
357
354
|
return template.replace("{{CANOPY_IMPORT}}", options.canopyImport);
|
|
358
355
|
}
|
|
359
356
|
async function editPage(options) {
|
|
360
|
-
const
|
|
357
|
+
const templateName = options.authProvider === "dev" ? "edit-page-dev.tsx.template" : "edit-page.tsx.template";
|
|
358
|
+
const template = await readTemplate(templateName);
|
|
361
359
|
return template.replace("{{CONFIG_IMPORT}}", options.configImport);
|
|
362
360
|
}
|
|
363
361
|
async function aiConfig() {
|
|
@@ -367,6 +365,14 @@ async function aiRoute(options) {
|
|
|
367
365
|
const template = await readTemplate("ai-route.ts.template");
|
|
368
366
|
return template.replace("{{CONFIG_IMPORT}}", options.configImport);
|
|
369
367
|
}
|
|
368
|
+
async function middleware(options) {
|
|
369
|
+
const templateName = options.authProvider === "clerk" ? "middleware-clerk.ts.template" : "middleware.ts.template";
|
|
370
|
+
return readTemplate(templateName);
|
|
371
|
+
}
|
|
372
|
+
async function nextConfig(options) {
|
|
373
|
+
const templateName = options.staticBuild ? "next.config-static.ts.template" : "next.config.ts.template";
|
|
374
|
+
return readTemplate(templateName);
|
|
375
|
+
}
|
|
370
376
|
async function dockerfileCms() {
|
|
371
377
|
return readTemplate("Dockerfile.cms.template");
|
|
372
378
|
}
|
|
@@ -402,7 +408,7 @@ function getTaskQueueDir(config) {
|
|
|
402
408
|
var init_task_queue_config = __esm({
|
|
403
409
|
"dist/worker/task-queue-config.js"() {
|
|
404
410
|
"use strict";
|
|
405
|
-
|
|
411
|
+
init_config2();
|
|
406
412
|
}
|
|
407
413
|
});
|
|
408
414
|
|
|
@@ -974,7 +980,7 @@ var DevClientSafeStrategy = class {
|
|
|
974
980
|
|
|
975
981
|
// dist/operating-mode/client-unsafe-strategy.js
|
|
976
982
|
import path from "node:path";
|
|
977
|
-
|
|
983
|
+
init_config2();
|
|
978
984
|
var ProdStrategy = class extends ProdClientSafeStrategy {
|
|
979
985
|
// All client-safe methods inherited automatically from ProdClientSafeStrategy:
|
|
980
986
|
// - mode, supportsBranching(), supportsStatusBadge(), supportsComments()
|
|
@@ -1162,19 +1168,59 @@ function configImportPath(appDir, subdirs) {
|
|
|
1162
1168
|
async function init(options) {
|
|
1163
1169
|
const { projectDir, mode, appDir, ai, force, nonInteractive } = options;
|
|
1164
1170
|
const writeOpts = { force, nonInteractive };
|
|
1165
|
-
const { canopyCmsConfig: canopyCmsConfig2, canopyContext: canopyContext2, schemasTemplate: schemasTemplate2, apiRoute: apiRoute2, editPage: editPage2, aiConfig: aiConfig2, aiRoute: aiRoute2 } = await Promise.resolve().then(() => (init_templates(), templates_exports));
|
|
1171
|
+
const { canopyCmsConfig: canopyCmsConfig2, canopyContext: canopyContext2, schemasTemplate: schemasTemplate2, apiRoute: apiRoute2, editPage: editPage2, aiConfig: aiConfig2, aiRoute: aiRoute2, nextConfig: nextConfig2, middleware: middleware2 } = await Promise.resolve().then(() => (init_templates(), templates_exports));
|
|
1166
1172
|
p.intro("CanopyCMS init");
|
|
1173
|
+
let authProvider;
|
|
1174
|
+
if (options.authProvider) {
|
|
1175
|
+
authProvider = options.authProvider;
|
|
1176
|
+
} else if (nonInteractive) {
|
|
1177
|
+
authProvider = "dev";
|
|
1178
|
+
} else {
|
|
1179
|
+
const choice = await p.select({
|
|
1180
|
+
message: "Which auth provider will you use in production?",
|
|
1181
|
+
options: [
|
|
1182
|
+
{ value: "clerk", label: "Clerk (+ dev auth for local development)" },
|
|
1183
|
+
{ value: "dev", label: "Dev auth only" }
|
|
1184
|
+
],
|
|
1185
|
+
initialValue: "dev"
|
|
1186
|
+
});
|
|
1187
|
+
if (p.isCancel(choice)) {
|
|
1188
|
+
p.cancel("Init cancelled");
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
authProvider = choice;
|
|
1192
|
+
}
|
|
1193
|
+
let staticBuild;
|
|
1194
|
+
if (options.staticBuild !== void 0) {
|
|
1195
|
+
staticBuild = options.staticBuild;
|
|
1196
|
+
} else if (nonInteractive) {
|
|
1197
|
+
staticBuild = false;
|
|
1198
|
+
} else {
|
|
1199
|
+
const choice = await p.confirm({
|
|
1200
|
+
message: "Will you use dual-build (static public site + server CMS build)?",
|
|
1201
|
+
initialValue: false
|
|
1202
|
+
});
|
|
1203
|
+
if (p.isCancel(choice)) {
|
|
1204
|
+
p.cancel("Init cancelled");
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
staticBuild = choice;
|
|
1208
|
+
}
|
|
1209
|
+
const serverPageExt = staticBuild ? "page.server.tsx" : "page.tsx";
|
|
1210
|
+
const serverRouteExt = staticBuild ? "route.server.ts" : "route.ts";
|
|
1167
1211
|
await writeFile(path6.join(projectDir, "canopycms.config.ts"), await canopyCmsConfig2({ mode }), writeOpts);
|
|
1168
|
-
await writeFile(path6.join(projectDir, appDir, "lib/canopy.ts"), await canopyContext2({ configImport: configImportPath(appDir, 1) }), writeOpts);
|
|
1212
|
+
await writeFile(path6.join(projectDir, appDir, "lib/canopy.ts"), await canopyContext2({ configImport: configImportPath(appDir, 1), authProvider }), writeOpts);
|
|
1169
1213
|
await writeFile(path6.join(projectDir, appDir, "schemas.ts"), await schemasTemplate2(), writeOpts);
|
|
1170
|
-
await writeFile(path6.join(projectDir, appDir,
|
|
1214
|
+
await writeFile(path6.join(projectDir, appDir, `api/canopycms/[...canopycms]/${serverRouteExt}`), await apiRoute2({
|
|
1171
1215
|
canopyImport: "../".repeat(3) + "lib/canopy"
|
|
1172
1216
|
}), writeOpts);
|
|
1173
|
-
await writeFile(path6.join(projectDir, appDir,
|
|
1217
|
+
await writeFile(path6.join(projectDir, appDir, `edit/${serverPageExt}`), await editPage2({ configImport: configImportPath(appDir, 1), authProvider }), writeOpts);
|
|
1174
1218
|
if (ai) {
|
|
1175
1219
|
await writeFile(path6.join(projectDir, appDir, "ai/config.ts"), await aiConfig2(), writeOpts);
|
|
1176
1220
|
await writeFile(path6.join(projectDir, appDir, "ai/[...path]/route.ts"), await aiRoute2({ configImport: configImportPath(appDir, 2) }), writeOpts);
|
|
1177
1221
|
}
|
|
1222
|
+
await writeFile(path6.join(projectDir, "next.config.ts"), await nextConfig2({ staticBuild }), writeOpts);
|
|
1223
|
+
await writeFile(path6.join(projectDir, "middleware.ts"), await middleware2({ authProvider }), writeOpts);
|
|
1178
1224
|
const gitignorePath = path6.join(projectDir, ".gitignore");
|
|
1179
1225
|
if (await filePathExists(gitignorePath)) {
|
|
1180
1226
|
const content = await fs5.readFile(gitignorePath, "utf-8");
|
|
@@ -1183,18 +1229,15 @@ async function init(options) {
|
|
|
1183
1229
|
p.log.success("updated: .gitignore");
|
|
1184
1230
|
}
|
|
1185
1231
|
}
|
|
1232
|
+
const packages = authProvider === "clerk" ? "canopycms canopycms-next canopycms-auth-clerk canopycms-auth-dev" : "canopycms canopycms-next canopycms-auth-dev";
|
|
1186
1233
|
p.note([
|
|
1187
1234
|
"1. Install dependencies:",
|
|
1188
|
-
` npm install
|
|
1189
|
-
"",
|
|
1190
|
-
"2. Wrap your Next.js config:",
|
|
1191
|
-
" import { withCanopy } from 'canopycms-next'",
|
|
1192
|
-
" export default withCanopy({ /* your config */ })",
|
|
1235
|
+
` npm install ${packages}`,
|
|
1193
1236
|
"",
|
|
1194
|
-
"
|
|
1237
|
+
"2. Customize " + appDir + "/schemas.ts with your content schema",
|
|
1195
1238
|
"",
|
|
1196
|
-
"
|
|
1197
|
-
"
|
|
1239
|
+
"3. Run: npm run dev",
|
|
1240
|
+
"4. Visit: http://localhost:3000/edit"
|
|
1198
1241
|
].join("\n"), "Next steps");
|
|
1199
1242
|
p.outro("Done!");
|
|
1200
1243
|
}
|
package/dist/cli/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAA;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/sync.js
CHANGED
|
@@ -16,7 +16,7 @@ import fs from 'node:fs/promises';
|
|
|
16
16
|
import path from 'node:path';
|
|
17
17
|
import { simpleGit } from 'simple-git';
|
|
18
18
|
import * as p from '@clack/prompts';
|
|
19
|
-
import { filePathExists } from '../utils/fs';
|
|
19
|
+
import { filePathExists } from '../utils/fs.js';
|
|
20
20
|
/** Validate that a resolved path stays within the expected parent directory. */
|
|
21
21
|
function assertWithinDir(resolved, parent, label) {
|
|
22
22
|
const normalizedResolved = path.resolve(resolved);
|
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
import { createNextCanopyContext } from 'canopycms-next'
|
|
2
|
-
|
|
3
|
-
import { createDevAuthPlugin } from 'canopycms-auth-dev'
|
|
2
|
+
{{AUTH_IMPORTS}}
|
|
4
3
|
import config from '{{CONFIG_IMPORT}}'
|
|
5
4
|
import { entrySchemaRegistry } from '../schemas'
|
|
6
5
|
|
|
7
6
|
const canopyContextPromise = createNextCanopyContext({
|
|
8
7
|
config: config.server,
|
|
9
|
-
authPlugin:
|
|
10
|
-
process.env.CANOPY_AUTH_MODE === 'clerk'
|
|
11
|
-
? createClerkAuthPlugin({ useOrganizationsAsGroups: true })
|
|
12
|
-
: createDevAuthPlugin(),
|
|
8
|
+
authPlugin: {{AUTH_PLUGIN}},
|
|
13
9
|
entrySchemaRegistry,
|
|
14
10
|
})
|
|
15
11
|
|
|
12
|
+
// Export for server component pages
|
|
16
13
|
export const getCanopy = async () => {
|
|
17
14
|
const context = await canopyContextPromise
|
|
18
15
|
return context.getCanopy()
|
|
19
16
|
}
|
|
20
17
|
|
|
18
|
+
// Export for build-time functions (generateStaticParams, generateMetadata)
|
|
19
|
+
export const getCanopyForBuild = async () => {
|
|
20
|
+
const context = await canopyContextPromise
|
|
21
|
+
return context.getCanopyForBuild()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Export for API routes
|
|
21
25
|
export const getHandler = async () => {
|
|
22
26
|
const context = await canopyContextPromise
|
|
23
27
|
return context.handler
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import type { CanopyClientConfig } from 'canopycms'
|
|
5
|
+
import { useDevAuthConfig } from 'canopycms-auth-dev/client'
|
|
6
|
+
import { NextCanopyEditorPage } from 'canopycms-next/client'
|
|
7
|
+
import config from '{{CONFIG_IMPORT}}'
|
|
8
|
+
|
|
9
|
+
function EditPageWithAuth({ authConfig }: { authConfig: Pick<CanopyClientConfig, 'editor'> }) {
|
|
10
|
+
const [EditorPage] = useState(() => NextCanopyEditorPage(config.client(authConfig)))
|
|
11
|
+
return <EditorPage />
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default function EditPage() {
|
|
15
|
+
return <EditPageWithAuth authConfig={useDevAuthConfig()} />
|
|
16
|
+
}
|
|
@@ -1,32 +1,25 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import type { CanopyClientConfig } from 'canopycms'
|
|
4
5
|
import { useDevAuthConfig } from 'canopycms-auth-dev/client'
|
|
6
|
+
import { useClerkAuthConfig } from 'canopycms-auth-clerk/client'
|
|
5
7
|
import { NextCanopyEditorPage } from 'canopycms-next/client'
|
|
6
8
|
import config from '{{CONFIG_IMPORT}}'
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
const authMode = process.env.NEXT_PUBLIC_CANOPY_AUTH_MODE || 'dev'
|
|
10
|
-
|
|
11
|
-
if (authMode === 'dev') {
|
|
12
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
13
|
-
return useDevAuthConfig()
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (authMode === 'clerk') {
|
|
17
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
18
|
-
return useClerkAuthConfig()
|
|
19
|
-
}
|
|
10
|
+
const authMode = process.env.NEXT_PUBLIC_CANOPY_AUTH_MODE || 'dev'
|
|
20
11
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
function EditPageWithAuth({ authConfig }: { authConfig: Pick<CanopyClientConfig, 'editor'> }) {
|
|
13
|
+
const [EditorPage] = useState(() => NextCanopyEditorPage(config.client(authConfig)))
|
|
14
|
+
return <EditorPage />
|
|
24
15
|
}
|
|
25
16
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
function DevEditPage() {
|
|
18
|
+
return <EditPageWithAuth authConfig={useDevAuthConfig()} />
|
|
19
|
+
}
|
|
29
20
|
|
|
30
|
-
|
|
31
|
-
return <
|
|
21
|
+
function ClerkEditPage() {
|
|
22
|
+
return <EditPageWithAuth authConfig={useClerkAuthConfig()} />
|
|
32
23
|
}
|
|
24
|
+
|
|
25
|
+
export default authMode === 'clerk' ? ClerkEditPage : DevEditPage
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
|
|
2
|
+
|
|
3
|
+
const isProtectedRoute = createRouteMatcher(['/edit(.*)', '/api/canopycms(.*)'])
|
|
4
|
+
|
|
5
|
+
export default clerkMiddleware(async (auth, req) => {
|
|
6
|
+
if (isProtectedRoute(req)) {
|
|
7
|
+
await auth.protect()
|
|
8
|
+
}
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
export const config = {
|
|
12
|
+
matcher: ['/edit(.*)', '/api/canopycms(.*)'],
|
|
13
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
|
|
3
|
+
// Protect CMS routes from unauthenticated access.
|
|
4
|
+
//
|
|
5
|
+
// For dev auth mode, no middleware protection is needed — this file is a passthrough.
|
|
6
|
+
// If you don't need auth protection, you can delete this file entirely.
|
|
7
|
+
//
|
|
8
|
+
// For Clerk auth, replace this file's contents with:
|
|
9
|
+
//
|
|
10
|
+
// import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
|
|
11
|
+
//
|
|
12
|
+
// const isProtectedRoute = createRouteMatcher(['/edit(.*)', '/api/canopycms(.*)'])
|
|
13
|
+
//
|
|
14
|
+
// export default clerkMiddleware(async (auth, req) => {
|
|
15
|
+
// if (isProtectedRoute(req)) {
|
|
16
|
+
// await auth.protect()
|
|
17
|
+
// }
|
|
18
|
+
// })
|
|
19
|
+
//
|
|
20
|
+
// export const config = {
|
|
21
|
+
// matcher: ['/edit(.*)', '/api/canopycms(.*)'],
|
|
22
|
+
// }
|
|
23
|
+
|
|
24
|
+
export default function middleware() {
|
|
25
|
+
return NextResponse.next()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const config = {
|
|
29
|
+
matcher: ['/edit(.*)', '/api/canopycms(.*)'],
|
|
30
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { withCanopy } from 'canopycms-next'
|
|
2
|
+
|
|
3
|
+
const isCmsBuild = process.env.CANOPY_BUILD === 'cms'
|
|
4
|
+
|
|
5
|
+
// Dual-build: static export for the public site, standalone Node.js server for the CMS.
|
|
6
|
+
// If deploying the CMS build to Vercel or another platform that doesn't use standalone,
|
|
7
|
+
// change 'standalone' to the appropriate output mode for your platform.
|
|
8
|
+
export default withCanopy(
|
|
9
|
+
{
|
|
10
|
+
output: isCmsBuild ? 'standalone' : 'export',
|
|
11
|
+
},
|
|
12
|
+
{ staticBuild: !isCmsBuild },
|
|
13
|
+
)
|