convex-cms 0.0.1
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/dist/cli/commands/admin.d.ts +16 -0
- package/dist/cli/commands/admin.d.ts.map +1 -0
- package/dist/cli/commands/admin.js +88 -0
- package/dist/cli/commands/admin.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +18 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/detectConvexUrl.d.ts +13 -0
- package/dist/cli/utils/detectConvexUrl.d.ts.map +1 -0
- package/dist/cli/utils/detectConvexUrl.js +48 -0
- package/dist/cli/utils/detectConvexUrl.js.map +1 -0
- package/dist/cli/utils/openBrowser.d.ts +7 -0
- package/dist/cli/utils/openBrowser.d.ts.map +1 -0
- package/dist/cli/utils/openBrowser.js +17 -0
- package/dist/cli/utils/openBrowser.js.map +1 -0
- package/dist/client/admin-config.d.ts +126 -0
- package/dist/client/admin-config.d.ts.map +1 -0
- package/dist/client/admin-config.js +117 -0
- package/dist/client/admin-config.js.map +1 -0
- package/dist/client/adminApi.d.ts +2273 -0
- package/dist/client/adminApi.d.ts.map +1 -0
- package/dist/client/adminApi.js +716 -0
- package/dist/client/adminApi.js.map +1 -0
- package/dist/client/agentTools.d.ts +933 -0
- package/dist/client/agentTools.d.ts.map +1 -0
- package/dist/client/agentTools.js +1004 -0
- package/dist/client/agentTools.js.map +1 -0
- package/dist/client/argTypes.d.ts +212 -0
- package/dist/client/argTypes.d.ts.map +1 -0
- package/dist/client/argTypes.js +5 -0
- package/dist/client/argTypes.js.map +1 -0
- package/dist/client/field-types.d.ts +55 -0
- package/dist/client/field-types.d.ts.map +1 -0
- package/dist/client/field-types.js +152 -0
- package/dist/client/field-types.js.map +1 -0
- package/dist/client/index.d.ts +189 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +668 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/queryBuilder.d.ts +765 -0
- package/dist/client/queryBuilder.d.ts.map +1 -0
- package/dist/client/queryBuilder.js +970 -0
- package/dist/client/queryBuilder.js.map +1 -0
- package/dist/client/schema/codegen.d.ts +128 -0
- package/dist/client/schema/codegen.d.ts.map +1 -0
- package/dist/client/schema/codegen.js +318 -0
- package/dist/client/schema/codegen.js.map +1 -0
- package/dist/client/schema/defineContentType.d.ts +221 -0
- package/dist/client/schema/defineContentType.d.ts.map +1 -0
- package/dist/client/schema/defineContentType.js +380 -0
- package/dist/client/schema/defineContentType.js.map +1 -0
- package/dist/client/schema/index.d.ts +85 -0
- package/dist/client/schema/index.d.ts.map +1 -0
- package/dist/client/schema/index.js +92 -0
- package/dist/client/schema/index.js.map +1 -0
- package/dist/client/schema/schemaDrift.d.ts +199 -0
- package/dist/client/schema/schemaDrift.d.ts.map +1 -0
- package/dist/client/schema/schemaDrift.js +340 -0
- package/dist/client/schema/schemaDrift.js.map +1 -0
- package/dist/client/schema/typedClient.d.ts +401 -0
- package/dist/client/schema/typedClient.d.ts.map +1 -0
- package/dist/client/schema/typedClient.js +269 -0
- package/dist/client/schema/typedClient.js.map +1 -0
- package/dist/client/schema/types.d.ts +477 -0
- package/dist/client/schema/types.d.ts.map +1 -0
- package/dist/client/schema/types.js +39 -0
- package/dist/client/schema/types.js.map +1 -0
- package/dist/client/types.d.ts +449 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +149 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/workflows.d.ts +51 -0
- package/dist/client/workflows.d.ts.map +1 -0
- package/dist/client/workflows.js +103 -0
- package/dist/client/workflows.js.map +1 -0
- package/dist/client/wrapper.d.ts +2198 -0
- package/dist/client/wrapper.d.ts.map +1 -0
- package/dist/client/wrapper.js +2651 -0
- package/dist/client/wrapper.js.map +1 -0
- package/dist/component/_generated/api.d.ts +124 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +4321 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +121 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +78 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/auditLog.d.ts +410 -0
- package/dist/component/auditLog.d.ts.map +1 -0
- package/dist/component/auditLog.js +607 -0
- package/dist/component/auditLog.js.map +1 -0
- package/dist/component/authorization.d.ts +323 -0
- package/dist/component/authorization.d.ts.map +1 -0
- package/dist/component/authorization.js +464 -0
- package/dist/component/authorization.js.map +1 -0
- package/dist/component/authorizationHooks.d.ts +184 -0
- package/dist/component/authorizationHooks.d.ts.map +1 -0
- package/dist/component/authorizationHooks.js +521 -0
- package/dist/component/authorizationHooks.js.map +1 -0
- package/dist/component/bulkOperations.d.ts +200 -0
- package/dist/component/bulkOperations.d.ts.map +1 -0
- package/dist/component/bulkOperations.js +568 -0
- package/dist/component/bulkOperations.js.map +1 -0
- package/dist/component/contentEntries.d.ts +719 -0
- package/dist/component/contentEntries.d.ts.map +1 -0
- package/dist/component/contentEntries.js +1617 -0
- package/dist/component/contentEntries.js.map +1 -0
- package/dist/component/contentEntryMutations.d.ts +505 -0
- package/dist/component/contentEntryMutations.d.ts.map +1 -0
- package/dist/component/contentEntryMutations.js +1009 -0
- package/dist/component/contentEntryMutations.js.map +1 -0
- package/dist/component/contentEntryValidation.d.ts +115 -0
- package/dist/component/contentEntryValidation.d.ts.map +1 -0
- package/dist/component/contentEntryValidation.js +546 -0
- package/dist/component/contentEntryValidation.js.map +1 -0
- package/dist/component/contentLock.d.ts +328 -0
- package/dist/component/contentLock.d.ts.map +1 -0
- package/dist/component/contentLock.js +471 -0
- package/dist/component/contentLock.js.map +1 -0
- package/dist/component/contentTypeMigration.d.ts +411 -0
- package/dist/component/contentTypeMigration.d.ts.map +1 -0
- package/dist/component/contentTypeMigration.js +805 -0
- package/dist/component/contentTypeMigration.js.map +1 -0
- package/dist/component/contentTypeMutations.d.ts +975 -0
- package/dist/component/contentTypeMutations.d.ts.map +1 -0
- package/dist/component/contentTypeMutations.js +768 -0
- package/dist/component/contentTypeMutations.js.map +1 -0
- package/dist/component/contentTypes.d.ts +538 -0
- package/dist/component/contentTypes.d.ts.map +1 -0
- package/dist/component/contentTypes.js +304 -0
- package/dist/component/contentTypes.js.map +1 -0
- package/dist/component/convex.config.d.ts +42 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +43 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/documentTypes.d.ts +186 -0
- package/dist/component/documentTypes.d.ts.map +1 -0
- package/dist/component/documentTypes.js +23 -0
- package/dist/component/documentTypes.js.map +1 -0
- package/dist/component/eventEmitter.d.ts +281 -0
- package/dist/component/eventEmitter.d.ts.map +1 -0
- package/dist/component/eventEmitter.js +300 -0
- package/dist/component/eventEmitter.js.map +1 -0
- package/dist/component/exportImport.d.ts +1120 -0
- package/dist/component/exportImport.d.ts.map +1 -0
- package/dist/component/exportImport.js +931 -0
- package/dist/component/exportImport.js.map +1 -0
- package/dist/component/index.d.ts +28 -0
- package/dist/component/index.d.ts.map +1 -0
- package/dist/component/index.js +142 -0
- package/dist/component/index.js.map +1 -0
- package/dist/component/lib/deepReferenceResolver.d.ts +252 -0
- package/dist/component/lib/deepReferenceResolver.d.ts.map +1 -0
- package/dist/component/lib/deepReferenceResolver.js +601 -0
- package/dist/component/lib/deepReferenceResolver.js.map +1 -0
- package/dist/component/lib/errors.d.ts +306 -0
- package/dist/component/lib/errors.d.ts.map +1 -0
- package/dist/component/lib/errors.js +407 -0
- package/dist/component/lib/errors.js.map +1 -0
- package/dist/component/lib/index.d.ts +10 -0
- package/dist/component/lib/index.d.ts.map +1 -0
- package/dist/component/lib/index.js +33 -0
- package/dist/component/lib/index.js.map +1 -0
- package/dist/component/lib/mediaReferenceResolver.d.ts +217 -0
- package/dist/component/lib/mediaReferenceResolver.d.ts.map +1 -0
- package/dist/component/lib/mediaReferenceResolver.js +326 -0
- package/dist/component/lib/mediaReferenceResolver.js.map +1 -0
- package/dist/component/lib/metadataExtractor.d.ts +245 -0
- package/dist/component/lib/metadataExtractor.d.ts.map +1 -0
- package/dist/component/lib/metadataExtractor.js +548 -0
- package/dist/component/lib/metadataExtractor.js.map +1 -0
- package/dist/component/lib/mutationAuth.d.ts +95 -0
- package/dist/component/lib/mutationAuth.d.ts.map +1 -0
- package/dist/component/lib/mutationAuth.js +146 -0
- package/dist/component/lib/mutationAuth.js.map +1 -0
- package/dist/component/lib/queries.d.ts +17 -0
- package/dist/component/lib/queries.d.ts.map +1 -0
- package/dist/component/lib/queries.js +49 -0
- package/dist/component/lib/queries.js.map +1 -0
- package/dist/component/lib/ragContentChunker.d.ts +423 -0
- package/dist/component/lib/ragContentChunker.d.ts.map +1 -0
- package/dist/component/lib/ragContentChunker.js +897 -0
- package/dist/component/lib/ragContentChunker.js.map +1 -0
- package/dist/component/lib/referenceResolver.d.ts +175 -0
- package/dist/component/lib/referenceResolver.d.ts.map +1 -0
- package/dist/component/lib/referenceResolver.js +293 -0
- package/dist/component/lib/referenceResolver.js.map +1 -0
- package/dist/component/lib/slugGenerator.d.ts +71 -0
- package/dist/component/lib/slugGenerator.d.ts.map +1 -0
- package/dist/component/lib/slugGenerator.js +207 -0
- package/dist/component/lib/slugGenerator.js.map +1 -0
- package/dist/component/lib/slugUniqueness.d.ts +131 -0
- package/dist/component/lib/slugUniqueness.d.ts.map +1 -0
- package/dist/component/lib/slugUniqueness.js +229 -0
- package/dist/component/lib/slugUniqueness.js.map +1 -0
- package/dist/component/lib/softDelete.d.ts +18 -0
- package/dist/component/lib/softDelete.d.ts.map +1 -0
- package/dist/component/lib/softDelete.js +29 -0
- package/dist/component/lib/softDelete.js.map +1 -0
- package/dist/component/localeFallbackChain.d.ts +410 -0
- package/dist/component/localeFallbackChain.d.ts.map +1 -0
- package/dist/component/localeFallbackChain.js +467 -0
- package/dist/component/localeFallbackChain.js.map +1 -0
- package/dist/component/localeFields.d.ts +508 -0
- package/dist/component/localeFields.d.ts.map +1 -0
- package/dist/component/localeFields.js +592 -0
- package/dist/component/localeFields.js.map +1 -0
- package/dist/component/mediaAssetMutations.d.ts +235 -0
- package/dist/component/mediaAssetMutations.d.ts.map +1 -0
- package/dist/component/mediaAssetMutations.js +558 -0
- package/dist/component/mediaAssetMutations.js.map +1 -0
- package/dist/component/mediaAssets.d.ts +168 -0
- package/dist/component/mediaAssets.d.ts.map +1 -0
- package/dist/component/mediaAssets.js +618 -0
- package/dist/component/mediaAssets.js.map +1 -0
- package/dist/component/mediaFolderMutations.d.ts +642 -0
- package/dist/component/mediaFolderMutations.d.ts.map +1 -0
- package/dist/component/mediaFolderMutations.js +849 -0
- package/dist/component/mediaFolderMutations.js.map +1 -0
- package/dist/component/mediaUploadMutations.d.ts +136 -0
- package/dist/component/mediaUploadMutations.d.ts.map +1 -0
- package/dist/component/mediaUploadMutations.js +205 -0
- package/dist/component/mediaUploadMutations.js.map +1 -0
- package/dist/component/mediaVariantMutations.d.ts +468 -0
- package/dist/component/mediaVariantMutations.d.ts.map +1 -0
- package/dist/component/mediaVariantMutations.js +737 -0
- package/dist/component/mediaVariantMutations.js.map +1 -0
- package/dist/component/mediaVariants.d.ts +525 -0
- package/dist/component/mediaVariants.d.ts.map +1 -0
- package/dist/component/mediaVariants.js +661 -0
- package/dist/component/mediaVariants.js.map +1 -0
- package/dist/component/ragContentIndexer.d.ts +595 -0
- package/dist/component/ragContentIndexer.d.ts.map +1 -0
- package/dist/component/ragContentIndexer.js +794 -0
- package/dist/component/ragContentIndexer.js.map +1 -0
- package/dist/component/rateLimitHooks.d.ts +266 -0
- package/dist/component/rateLimitHooks.d.ts.map +1 -0
- package/dist/component/rateLimitHooks.js +412 -0
- package/dist/component/rateLimitHooks.js.map +1 -0
- package/dist/component/roles.d.ts +649 -0
- package/dist/component/roles.d.ts.map +1 -0
- package/dist/component/roles.js +884 -0
- package/dist/component/roles.js.map +1 -0
- package/dist/component/scheduledPublish.d.ts +182 -0
- package/dist/component/scheduledPublish.d.ts.map +1 -0
- package/dist/component/scheduledPublish.js +304 -0
- package/dist/component/scheduledPublish.js.map +1 -0
- package/dist/component/schema.d.ts +4114 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +469 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/component/taxonomies.d.ts +476 -0
- package/dist/component/taxonomies.d.ts.map +1 -0
- package/dist/component/taxonomies.js +785 -0
- package/dist/component/taxonomies.js.map +1 -0
- package/dist/component/taxonomyMutations.d.ts +206 -0
- package/dist/component/taxonomyMutations.d.ts.map +1 -0
- package/dist/component/taxonomyMutations.js +1001 -0
- package/dist/component/taxonomyMutations.js.map +1 -0
- package/dist/component/trash.d.ts +265 -0
- package/dist/component/trash.d.ts.map +1 -0
- package/dist/component/trash.js +621 -0
- package/dist/component/trash.js.map +1 -0
- package/dist/component/types.d.ts +4 -0
- package/dist/component/types.d.ts.map +1 -0
- package/dist/component/types.js +2 -0
- package/dist/component/types.js.map +1 -0
- package/dist/component/userContext.d.ts +508 -0
- package/dist/component/userContext.d.ts.map +1 -0
- package/dist/component/userContext.js +615 -0
- package/dist/component/userContext.js.map +1 -0
- package/dist/component/validation.d.ts +387 -0
- package/dist/component/validation.d.ts.map +1 -0
- package/dist/component/validation.js +1052 -0
- package/dist/component/validation.js.map +1 -0
- package/dist/component/validators.d.ts +4645 -0
- package/dist/component/validators.d.ts.map +1 -0
- package/dist/component/validators.js +641 -0
- package/dist/component/validators.js.map +1 -0
- package/dist/component/versionMutations.d.ts +216 -0
- package/dist/component/versionMutations.d.ts.map +1 -0
- package/dist/component/versionMutations.js +321 -0
- package/dist/component/versionMutations.js.map +1 -0
- package/dist/component/webhookTrigger.d.ts +770 -0
- package/dist/component/webhookTrigger.d.ts.map +1 -0
- package/dist/component/webhookTrigger.js +1413 -0
- package/dist/component/webhookTrigger.js.map +1 -0
- package/dist/react/index.d.ts +316 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +558 -0
- package/dist/react/index.js.map +1 -0
- package/dist/test.d.ts +2230 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +1107 -0
- package/dist/test.js.map +1 -0
- package/package.json +95 -0
- package/src/cli/commands/admin.ts +104 -0
- package/src/cli/index.ts +21 -0
- package/src/cli/utils/detectConvexUrl.ts +54 -0
- package/src/cli/utils/openBrowser.ts +16 -0
- package/src/client/admin-config.ts +138 -0
- package/src/client/adminApi.ts +942 -0
- package/src/client/agentTools.ts +1311 -0
- package/src/client/argTypes.ts +316 -0
- package/src/client/field-types.ts +187 -0
- package/src/client/index.ts +1301 -0
- package/src/client/queryBuilder.ts +1100 -0
- package/src/client/schema/codegen.ts +500 -0
- package/src/client/schema/defineContentType.ts +501 -0
- package/src/client/schema/index.ts +169 -0
- package/src/client/schema/schemaDrift.ts +574 -0
- package/src/client/schema/typedClient.ts +688 -0
- package/src/client/schema/types.ts +666 -0
- package/src/client/types.ts +723 -0
- package/src/client/workflows.ts +141 -0
- package/src/client/wrapper.ts +4304 -0
- package/src/component/_generated/api.ts +140 -0
- package/src/component/_generated/component.ts +5029 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +156 -0
- package/src/component/authorization.ts +647 -0
- package/src/component/authorizationHooks.ts +668 -0
- package/src/component/bulkOperations.ts +687 -0
- package/src/component/contentEntries.ts +1976 -0
- package/src/component/contentEntryMutations.ts +1223 -0
- package/src/component/contentEntryValidation.ts +707 -0
- package/src/component/contentLock.ts +550 -0
- package/src/component/contentTypeMigration.ts +1064 -0
- package/src/component/contentTypeMutations.ts +969 -0
- package/src/component/contentTypes.ts +346 -0
- package/src/component/convex.config.ts +44 -0
- package/src/component/documentTypes.ts +240 -0
- package/src/component/eventEmitter.ts +485 -0
- package/src/component/exportImport.ts +1169 -0
- package/src/component/index.ts +491 -0
- package/src/component/lib/deepReferenceResolver.ts +999 -0
- package/src/component/lib/errors.ts +816 -0
- package/src/component/lib/index.ts +145 -0
- package/src/component/lib/mediaReferenceResolver.ts +495 -0
- package/src/component/lib/metadataExtractor.ts +792 -0
- package/src/component/lib/mutationAuth.ts +199 -0
- package/src/component/lib/queries.ts +79 -0
- package/src/component/lib/ragContentChunker.ts +1371 -0
- package/src/component/lib/referenceResolver.ts +430 -0
- package/src/component/lib/slugGenerator.ts +262 -0
- package/src/component/lib/slugUniqueness.ts +333 -0
- package/src/component/lib/softDelete.ts +44 -0
- package/src/component/localeFallbackChain.ts +673 -0
- package/src/component/localeFields.ts +896 -0
- package/src/component/mediaAssetMutations.ts +725 -0
- package/src/component/mediaAssets.ts +932 -0
- package/src/component/mediaFolderMutations.ts +1046 -0
- package/src/component/mediaUploadMutations.ts +224 -0
- package/src/component/mediaVariantMutations.ts +900 -0
- package/src/component/mediaVariants.ts +793 -0
- package/src/component/ragContentIndexer.ts +1067 -0
- package/src/component/rateLimitHooks.ts +572 -0
- package/src/component/roles.ts +1360 -0
- package/src/component/scheduledPublish.ts +358 -0
- package/src/component/schema.ts +617 -0
- package/src/component/taxonomies.ts +949 -0
- package/src/component/taxonomyMutations.ts +1210 -0
- package/src/component/trash.ts +724 -0
- package/src/component/userContext.ts +898 -0
- package/src/component/validation.ts +1388 -0
- package/src/component/validators.ts +949 -0
- package/src/component/versionMutations.ts +392 -0
- package/src/component/webhookTrigger.ts +1922 -0
- package/src/react/index.ts +898 -0
- package/src/test.ts +1580 -0
|
@@ -0,0 +1,688 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema-Aware Typed CMS Client
|
|
3
|
+
*
|
|
4
|
+
* This module provides type-safe access to content entries when a schema
|
|
5
|
+
* is configured. The types are inferred from the Convex validators defined
|
|
6
|
+
* in the schema.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { v } from "convex/values";
|
|
11
|
+
* import { defineContentType, createContentSchema, createTypedCmsClient } from "@convex-cms/core";
|
|
12
|
+
* import { components } from "./_generated/api";
|
|
13
|
+
*
|
|
14
|
+
* // Define content types with validators
|
|
15
|
+
* const blogPost = defineContentType({
|
|
16
|
+
* name: "blog_post",
|
|
17
|
+
* validator: v.object({ title: v.string(), content: v.string() }),
|
|
18
|
+
* meta: { displayName: "Blog Post" },
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* const contentSchema = createContentSchema({ blogPost });
|
|
22
|
+
*
|
|
23
|
+
* // Create a typed CMS client
|
|
24
|
+
* export const cms = createTypedCmsClient(components.convexCms, {
|
|
25
|
+
* schema: contentSchema,
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* // Now methods return typed data
|
|
29
|
+
* const post = await cms.contentEntries.get<"blog_post">(ctx, id);
|
|
30
|
+
* post.data.title // ✅ string - TypeScript knows the type
|
|
31
|
+
* post.data.typo // ❌ Error: Property 'typo' does not exist
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import type {
|
|
36
|
+
ContentTypeDefinition,
|
|
37
|
+
InferSchema,
|
|
38
|
+
SchemaContentTypeNames,
|
|
39
|
+
} from "./types.js";
|
|
40
|
+
import type { ContentEntry, ContentStatus, PaginationOpts } from "../types.js";
|
|
41
|
+
import type { ContentSchemaInstance } from "./defineContentType.js";
|
|
42
|
+
import type { ConvexContext } from "../wrapper.js";
|
|
43
|
+
|
|
44
|
+
// =============================================================================
|
|
45
|
+
// Typed Content Entry Types
|
|
46
|
+
// =============================================================================
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A content entry with typed data based on the schema.
|
|
50
|
+
*
|
|
51
|
+
* @typeParam TData - The inferred data type from the content type's validator
|
|
52
|
+
*/
|
|
53
|
+
export interface TypedContentEntry<TData extends Record<string, unknown>>
|
|
54
|
+
extends Omit<ContentEntry, "data"> {
|
|
55
|
+
/**
|
|
56
|
+
* The content data with full type inference.
|
|
57
|
+
*/
|
|
58
|
+
data: TData;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A paginated result with typed content entries.
|
|
63
|
+
*/
|
|
64
|
+
export interface TypedPaginationResult<TData extends Record<string, unknown>> {
|
|
65
|
+
page: TypedContentEntry<TData>[];
|
|
66
|
+
continueCursor: string | null;
|
|
67
|
+
isDone: boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// =============================================================================
|
|
71
|
+
// Schema Type Utilities
|
|
72
|
+
// =============================================================================
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Extract the data type for a content type name from a schema.
|
|
76
|
+
*/
|
|
77
|
+
export type SchemaDataType<
|
|
78
|
+
TSchema extends ContentSchemaInstance<Record<string, ContentTypeDefinition>>,
|
|
79
|
+
TName extends string
|
|
80
|
+
> = TSchema extends ContentSchemaInstance<infer TDefs>
|
|
81
|
+
? TName extends keyof InferSchema<TDefs>
|
|
82
|
+
? InferSchema<TDefs>[TName] extends Record<string, unknown>
|
|
83
|
+
? InferSchema<TDefs>[TName]
|
|
84
|
+
: Record<string, unknown>
|
|
85
|
+
: Record<string, unknown>
|
|
86
|
+
: Record<string, unknown>;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Extract all valid content type names from a schema.
|
|
90
|
+
*/
|
|
91
|
+
export type ValidContentTypeName<
|
|
92
|
+
TSchema extends ContentSchemaInstance<Record<string, ContentTypeDefinition>>
|
|
93
|
+
> = TSchema extends ContentSchemaInstance<infer TDefs>
|
|
94
|
+
? SchemaContentTypeNames<TDefs>
|
|
95
|
+
: string;
|
|
96
|
+
|
|
97
|
+
// =============================================================================
|
|
98
|
+
// Typed Content Entries API Interface
|
|
99
|
+
// =============================================================================
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Typed content entries API methods.
|
|
103
|
+
*
|
|
104
|
+
* These methods provide full type inference for content data when a schema
|
|
105
|
+
* is configured.
|
|
106
|
+
*
|
|
107
|
+
* @typeParam TSchema - The content schema instance type
|
|
108
|
+
*/
|
|
109
|
+
export interface TypedContentEntriesApi<
|
|
110
|
+
TSchema extends ContentSchemaInstance<Record<string, ContentTypeDefinition>>
|
|
111
|
+
> {
|
|
112
|
+
/**
|
|
113
|
+
* Get a content entry by ID with typed data.
|
|
114
|
+
*
|
|
115
|
+
* @param ctx - Convex context
|
|
116
|
+
* @param id - The content entry ID
|
|
117
|
+
* @returns The entry with typed data, or null if not found
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* const post = await cms.contentEntries.get<"blog_post">(ctx, id);
|
|
122
|
+
* if (post) {
|
|
123
|
+
* console.log(post.data.title); // ✅ TypeScript knows title is string
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
get<TName extends ValidContentTypeName<TSchema>>(
|
|
128
|
+
ctx: ConvexContext,
|
|
129
|
+
id: string,
|
|
130
|
+
): Promise<TypedContentEntry<SchemaDataType<TSchema, TName>> | null>;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Get a content entry by slug with typed data.
|
|
134
|
+
*
|
|
135
|
+
* @param ctx - Convex context
|
|
136
|
+
* @param options - Query options including contentTypeName and slug
|
|
137
|
+
* @returns The entry with typed data, or null if not found
|
|
138
|
+
*/
|
|
139
|
+
getBySlug<TName extends ValidContentTypeName<TSchema>>(
|
|
140
|
+
ctx: ConvexContext,
|
|
141
|
+
options: {
|
|
142
|
+
contentTypeName: TName;
|
|
143
|
+
slug: string;
|
|
144
|
+
locale?: string;
|
|
145
|
+
status?: ContentStatus | ContentStatus[];
|
|
146
|
+
},
|
|
147
|
+
): Promise<TypedContentEntry<SchemaDataType<TSchema, TName>> | null>;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Create a new content entry with typed data.
|
|
151
|
+
*
|
|
152
|
+
* @param ctx - Convex context
|
|
153
|
+
* @param options - Creation options including typed data
|
|
154
|
+
* @returns The created entry with typed data
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```typescript
|
|
158
|
+
* const post = await cms.contentEntries.create<"blog_post">(ctx, {
|
|
159
|
+
* contentTypeName: "blog_post",
|
|
160
|
+
* data: {
|
|
161
|
+
* title: "Hello World", // ✅ TypeScript validates this
|
|
162
|
+
* typo: "oops", // ❌ Error: 'typo' does not exist
|
|
163
|
+
* },
|
|
164
|
+
* });
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
create<TName extends ValidContentTypeName<TSchema>>(
|
|
168
|
+
ctx: ConvexContext,
|
|
169
|
+
options: TypedCreateEntryOptions<TSchema, TName>,
|
|
170
|
+
): Promise<TypedContentEntry<SchemaDataType<TSchema, TName>>>;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Update an existing content entry with typed data.
|
|
174
|
+
*
|
|
175
|
+
* @param ctx - Convex context
|
|
176
|
+
* @param options - Update options including partial typed data
|
|
177
|
+
* @returns The updated entry with typed data
|
|
178
|
+
*/
|
|
179
|
+
update<TName extends ValidContentTypeName<TSchema>>(
|
|
180
|
+
ctx: ConvexContext,
|
|
181
|
+
options: TypedUpdateEntryOptions<TSchema, TName>,
|
|
182
|
+
): Promise<TypedContentEntry<SchemaDataType<TSchema, TName>>>;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* List content entries with typed data.
|
|
186
|
+
*
|
|
187
|
+
* @param ctx - Convex context
|
|
188
|
+
* @param options - List options
|
|
189
|
+
* @returns Paginated results with typed entries
|
|
190
|
+
*/
|
|
191
|
+
list<TName extends ValidContentTypeName<TSchema>>(
|
|
192
|
+
ctx: ConvexContext,
|
|
193
|
+
options: TypedListEntriesOptions<TName>,
|
|
194
|
+
): Promise<TypedPaginationResult<SchemaDataType<TSchema, TName>>>;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// =============================================================================
|
|
198
|
+
// Typed Method Options
|
|
199
|
+
// =============================================================================
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Options for creating a content entry with typed data.
|
|
203
|
+
*/
|
|
204
|
+
export interface TypedCreateEntryOptions<
|
|
205
|
+
TSchema extends ContentSchemaInstance<Record<string, ContentTypeDefinition>>,
|
|
206
|
+
TName extends ValidContentTypeName<TSchema>
|
|
207
|
+
> {
|
|
208
|
+
/**
|
|
209
|
+
* The content type name (must match a type in the schema).
|
|
210
|
+
*/
|
|
211
|
+
contentTypeName: TName;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* The content data (fully typed based on the content type's validator).
|
|
215
|
+
*/
|
|
216
|
+
data: SchemaDataType<TSchema, TName>;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Optional slug (auto-generated if not provided).
|
|
220
|
+
*/
|
|
221
|
+
slug?: string;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Optional locale for localized content.
|
|
225
|
+
*/
|
|
226
|
+
locale?: string;
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* User ID of the creator.
|
|
230
|
+
*/
|
|
231
|
+
createdBy?: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Options for updating a content entry with typed data.
|
|
236
|
+
*/
|
|
237
|
+
export interface TypedUpdateEntryOptions<
|
|
238
|
+
TSchema extends ContentSchemaInstance<Record<string, ContentTypeDefinition>>,
|
|
239
|
+
TName extends ValidContentTypeName<TSchema>
|
|
240
|
+
> {
|
|
241
|
+
/**
|
|
242
|
+
* The content entry ID.
|
|
243
|
+
*/
|
|
244
|
+
id: string;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Partial content data (typed based on the content type).
|
|
248
|
+
*/
|
|
249
|
+
data?: Partial<SchemaDataType<TSchema, TName>>;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Optional updated slug.
|
|
253
|
+
*/
|
|
254
|
+
slug?: string;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* User ID of the updater.
|
|
258
|
+
*/
|
|
259
|
+
updatedBy?: string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Options for listing content entries with typed results.
|
|
264
|
+
*/
|
|
265
|
+
export interface TypedListEntriesOptions<TName extends string> {
|
|
266
|
+
/**
|
|
267
|
+
* Filter by content type name.
|
|
268
|
+
*/
|
|
269
|
+
contentTypeName?: TName;
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Filter by status.
|
|
273
|
+
*/
|
|
274
|
+
status?: ContentStatus;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Filter by multiple statuses.
|
|
278
|
+
*/
|
|
279
|
+
statusIn?: ContentStatus[];
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Filter by locale.
|
|
283
|
+
*/
|
|
284
|
+
locale?: string;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Search query.
|
|
288
|
+
*/
|
|
289
|
+
search?: string;
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Include soft-deleted entries.
|
|
293
|
+
*/
|
|
294
|
+
includeDeleted?: boolean;
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Pagination options.
|
|
298
|
+
*/
|
|
299
|
+
paginationOpts: PaginationOpts;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// =============================================================================
|
|
303
|
+
// Type Helpers for Schema Integration
|
|
304
|
+
// =============================================================================
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Helper type to check if a schema has a specific content type.
|
|
308
|
+
*/
|
|
309
|
+
export type HasContentType<
|
|
310
|
+
TSchema extends ContentSchemaInstance<Record<string, ContentTypeDefinition>>,
|
|
311
|
+
TName extends string
|
|
312
|
+
> = TName extends ValidContentTypeName<TSchema> ? true : false;
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Utility type to get the definition for a specific content type.
|
|
316
|
+
*/
|
|
317
|
+
export type GetContentTypeDefinition<
|
|
318
|
+
TSchema extends ContentSchemaInstance<Record<string, ContentTypeDefinition>>,
|
|
319
|
+
TName extends string
|
|
320
|
+
> = TSchema extends ContentSchemaInstance<infer TDefs>
|
|
321
|
+
? {
|
|
322
|
+
[K in keyof TDefs]: TDefs[K] extends ContentTypeDefinition<
|
|
323
|
+
TName,
|
|
324
|
+
infer _V
|
|
325
|
+
>
|
|
326
|
+
? TDefs[K]
|
|
327
|
+
: never;
|
|
328
|
+
}[keyof TDefs]
|
|
329
|
+
: never;
|
|
330
|
+
|
|
331
|
+
// =============================================================================
|
|
332
|
+
// Typed CMS Client Factory
|
|
333
|
+
// =============================================================================
|
|
334
|
+
|
|
335
|
+
import type { ComponentConfig } from "../types.js";
|
|
336
|
+
import type { TypedComponentApi, CmsClient } from "../wrapper.js";
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Configuration for creating a typed CMS client.
|
|
340
|
+
*/
|
|
341
|
+
export interface TypedCmsClientConfig<
|
|
342
|
+
TSchema extends ContentSchemaInstance<Record<string, ContentTypeDefinition>>
|
|
343
|
+
> extends ComponentConfig {
|
|
344
|
+
/**
|
|
345
|
+
* The content schema instance containing type definitions.
|
|
346
|
+
* Created using `createContentSchema()`.
|
|
347
|
+
*/
|
|
348
|
+
schema: TSchema;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* A typed CMS client with schema-aware content entry methods.
|
|
353
|
+
*
|
|
354
|
+
* @typeParam TSchema - The content schema instance type
|
|
355
|
+
*/
|
|
356
|
+
export interface TypedCmsClient<
|
|
357
|
+
TSchema extends ContentSchemaInstance<Record<string, ContentTypeDefinition>>
|
|
358
|
+
> extends CmsClient {
|
|
359
|
+
/**
|
|
360
|
+
* The content schema configured for this client.
|
|
361
|
+
*/
|
|
362
|
+
readonly schema: TSchema;
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Typed content entries API with methods that return properly typed data.
|
|
366
|
+
*/
|
|
367
|
+
readonly typedContentEntries: TypedContentEntriesApiImpl<TSchema>;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Implementation of typed content entries API.
|
|
372
|
+
*
|
|
373
|
+
* This provides typed wrappers around the base content entries API that
|
|
374
|
+
* cast results to the appropriate types based on the schema.
|
|
375
|
+
*
|
|
376
|
+
* @typeParam TSchema - The content schema instance type
|
|
377
|
+
*/
|
|
378
|
+
export class TypedContentEntriesApiImpl<
|
|
379
|
+
TSchema extends ContentSchemaInstance<Record<string, ContentTypeDefinition>>
|
|
380
|
+
> {
|
|
381
|
+
private baseClient: CmsClient;
|
|
382
|
+
private schema: TSchema;
|
|
383
|
+
|
|
384
|
+
constructor(baseClient: CmsClient, schema: TSchema) {
|
|
385
|
+
this.baseClient = baseClient;
|
|
386
|
+
this.schema = schema;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Get a content entry by ID with typed data.
|
|
391
|
+
*
|
|
392
|
+
* @param ctx - Convex context
|
|
393
|
+
* @param id - The content entry ID
|
|
394
|
+
* @returns The entry with typed data, or null if not found
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* ```typescript
|
|
398
|
+
* const post = await cms.typedContentEntries.get<"blog_post">(ctx, id);
|
|
399
|
+
* if (post) {
|
|
400
|
+
* console.log(post.data.title); // ✅ TypeScript knows title is string
|
|
401
|
+
* }
|
|
402
|
+
* ```
|
|
403
|
+
*/
|
|
404
|
+
async get<TName extends ValidContentTypeName<TSchema>>(
|
|
405
|
+
ctx: ConvexContext,
|
|
406
|
+
id: string,
|
|
407
|
+
): Promise<TypedContentEntry<SchemaDataType<TSchema, TName>> | null> {
|
|
408
|
+
const entry = await this.baseClient.contentEntries.get(ctx, { id });
|
|
409
|
+
if (!entry) return null;
|
|
410
|
+
|
|
411
|
+
// Cast to typed entry - the data shape is validated at write time
|
|
412
|
+
return (entry as unknown) as TypedContentEntry<
|
|
413
|
+
SchemaDataType<TSchema, TName>
|
|
414
|
+
>;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Get a content entry by slug with typed data.
|
|
419
|
+
*
|
|
420
|
+
* @param ctx - Convex context
|
|
421
|
+
* @param options - Query options including contentTypeName and slug
|
|
422
|
+
* @returns The entry with typed data, or null if not found
|
|
423
|
+
*/
|
|
424
|
+
async getBySlug<TName extends ValidContentTypeName<TSchema>>(
|
|
425
|
+
ctx: ConvexContext,
|
|
426
|
+
options: {
|
|
427
|
+
contentTypeName: TName;
|
|
428
|
+
slug: string;
|
|
429
|
+
locale?: string;
|
|
430
|
+
},
|
|
431
|
+
): Promise<TypedContentEntry<SchemaDataType<TSchema, TName>> | null> {
|
|
432
|
+
const entry = await this.baseClient.contentEntries.getBySlug(ctx, {
|
|
433
|
+
contentTypeName: options.contentTypeName,
|
|
434
|
+
slug: options.slug,
|
|
435
|
+
locale: options.locale,
|
|
436
|
+
});
|
|
437
|
+
if (!entry) return null;
|
|
438
|
+
|
|
439
|
+
return (entry as unknown) as TypedContentEntry<
|
|
440
|
+
SchemaDataType<TSchema, TName>
|
|
441
|
+
>;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Create a new content entry with typed data.
|
|
446
|
+
*
|
|
447
|
+
* @param ctx - Convex context
|
|
448
|
+
* @param options - Creation options including typed data
|
|
449
|
+
* @returns The created entry with typed data
|
|
450
|
+
*
|
|
451
|
+
* @example
|
|
452
|
+
* ```typescript
|
|
453
|
+
* const post = await cms.typedContentEntries.create<"blog_post">(ctx, {
|
|
454
|
+
* contentTypeName: "blog_post",
|
|
455
|
+
* data: {
|
|
456
|
+
* title: "Hello World", // ✅ TypeScript validates this
|
|
457
|
+
* content: "...",
|
|
458
|
+
* },
|
|
459
|
+
* });
|
|
460
|
+
* ```
|
|
461
|
+
*/
|
|
462
|
+
async create<TName extends ValidContentTypeName<TSchema>>(
|
|
463
|
+
ctx: ConvexContext,
|
|
464
|
+
options: TypedCreateEntryOptions<TSchema, TName>,
|
|
465
|
+
): Promise<TypedContentEntry<SchemaDataType<TSchema, TName>>> {
|
|
466
|
+
// Look up the content type by name to get its ID
|
|
467
|
+
const contentType = await this.baseClient.contentTypes.getByName(
|
|
468
|
+
ctx,
|
|
469
|
+
options.contentTypeName as string,
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
if (!contentType) {
|
|
473
|
+
throw new Error(`Content type "${options.contentTypeName}" not found`);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const entry = await this.baseClient.contentEntries.create(ctx, {
|
|
477
|
+
contentTypeId: contentType._id,
|
|
478
|
+
data: options.data as Record<string, unknown>,
|
|
479
|
+
slug: options.slug,
|
|
480
|
+
locale: options.locale,
|
|
481
|
+
createdBy: options.createdBy,
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
return (entry as unknown) as TypedContentEntry<
|
|
485
|
+
SchemaDataType<TSchema, TName>
|
|
486
|
+
>;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Update an existing content entry with typed data.
|
|
491
|
+
*
|
|
492
|
+
* @param ctx - Convex context
|
|
493
|
+
* @param options - Update options including partial typed data
|
|
494
|
+
* @returns The updated entry with typed data
|
|
495
|
+
*/
|
|
496
|
+
async update<TName extends ValidContentTypeName<TSchema>>(
|
|
497
|
+
ctx: ConvexContext,
|
|
498
|
+
options: TypedUpdateEntryOptions<TSchema, TName>,
|
|
499
|
+
): Promise<TypedContentEntry<SchemaDataType<TSchema, TName>>> {
|
|
500
|
+
const entry = await this.baseClient.contentEntries.update(ctx, {
|
|
501
|
+
id: options.id,
|
|
502
|
+
data: options.data as Record<string, unknown> | undefined,
|
|
503
|
+
slug: options.slug,
|
|
504
|
+
updatedBy: options.updatedBy,
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
return (entry as unknown) as TypedContentEntry<
|
|
508
|
+
SchemaDataType<TSchema, TName>
|
|
509
|
+
>;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* List content entries with typed data.
|
|
514
|
+
*
|
|
515
|
+
* @param ctx - Convex context
|
|
516
|
+
* @param options - List options
|
|
517
|
+
* @returns Paginated results with typed entries
|
|
518
|
+
*/
|
|
519
|
+
async list<TName extends ValidContentTypeName<TSchema>>(
|
|
520
|
+
ctx: ConvexContext,
|
|
521
|
+
options: TypedListEntriesOptions<TName>,
|
|
522
|
+
): Promise<TypedPaginationResult<SchemaDataType<TSchema, TName>>> {
|
|
523
|
+
// If filtering by content type name, look up the content type ID
|
|
524
|
+
let contentTypeId: string | undefined;
|
|
525
|
+
if (options.contentTypeName) {
|
|
526
|
+
const contentType = await this.baseClient.contentTypes.getByName(
|
|
527
|
+
ctx,
|
|
528
|
+
options.contentTypeName as string,
|
|
529
|
+
);
|
|
530
|
+
if (contentType) {
|
|
531
|
+
contentTypeId = contentType._id;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const result = await this.baseClient.contentEntries.list(ctx, {
|
|
536
|
+
contentTypeId,
|
|
537
|
+
status: options.status,
|
|
538
|
+
statusIn: options.statusIn,
|
|
539
|
+
locale: options.locale,
|
|
540
|
+
search: options.search,
|
|
541
|
+
includeDeleted: options.includeDeleted,
|
|
542
|
+
paginationOpts: options.paginationOpts,
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
return {
|
|
546
|
+
page: (result.page as unknown) as TypedContentEntry<
|
|
547
|
+
SchemaDataType<TSchema, TName>
|
|
548
|
+
>[],
|
|
549
|
+
continueCursor: result.continueCursor,
|
|
550
|
+
isDone: result.isDone,
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Publish a content entry.
|
|
556
|
+
*
|
|
557
|
+
* @param ctx - Convex context
|
|
558
|
+
* @param id - The entry ID to publish
|
|
559
|
+
* @param updatedBy - Optional user ID who triggered the publish
|
|
560
|
+
* @returns The published entry with typed data
|
|
561
|
+
*/
|
|
562
|
+
async publish<TName extends ValidContentTypeName<TSchema>>(
|
|
563
|
+
ctx: ConvexContext,
|
|
564
|
+
id: string,
|
|
565
|
+
updatedBy?: string,
|
|
566
|
+
): Promise<TypedContentEntry<SchemaDataType<TSchema, TName>>> {
|
|
567
|
+
const entry = await this.baseClient.contentEntries.publish(ctx, {
|
|
568
|
+
id,
|
|
569
|
+
updatedBy,
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
return (entry as unknown) as TypedContentEntry<
|
|
573
|
+
SchemaDataType<TSchema, TName>
|
|
574
|
+
>;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Unpublish a content entry.
|
|
579
|
+
*
|
|
580
|
+
* @param ctx - Convex context
|
|
581
|
+
* @param id - The entry ID to unpublish
|
|
582
|
+
* @param updatedBy - Optional user ID who triggered the unpublish
|
|
583
|
+
* @returns The unpublished entry with typed data
|
|
584
|
+
*/
|
|
585
|
+
async unpublish<TName extends ValidContentTypeName<TSchema>>(
|
|
586
|
+
ctx: ConvexContext,
|
|
587
|
+
id: string,
|
|
588
|
+
updatedBy?: string,
|
|
589
|
+
): Promise<TypedContentEntry<SchemaDataType<TSchema, TName>>> {
|
|
590
|
+
const entry = await this.baseClient.contentEntries.unpublish(ctx, {
|
|
591
|
+
id,
|
|
592
|
+
updatedBy,
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
return (entry as unknown) as TypedContentEntry<
|
|
596
|
+
SchemaDataType<TSchema, TName>
|
|
597
|
+
>;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Get the schema configured for this typed client.
|
|
602
|
+
*/
|
|
603
|
+
getSchema(): TSchema {
|
|
604
|
+
return this.schema;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Validate that a content type exists in the schema.
|
|
609
|
+
*
|
|
610
|
+
* @param name - The content type name to validate
|
|
611
|
+
* @returns true if the content type exists
|
|
612
|
+
*/
|
|
613
|
+
hasContentType(name: string): boolean {
|
|
614
|
+
return this.schema.hasContentType(name);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Creates a typed CMS client with schema-aware content entry methods.
|
|
620
|
+
*
|
|
621
|
+
* This is the main entry point for using type-safe content operations.
|
|
622
|
+
* The returned client extends the base `CmsClient` with additional
|
|
623
|
+
* `typedContentEntries` methods that provide full TypeScript inference.
|
|
624
|
+
*
|
|
625
|
+
* @param componentApi - The component API from `components.convexCms`
|
|
626
|
+
* @param config - Configuration including the content schema
|
|
627
|
+
* @returns A typed CMS client instance
|
|
628
|
+
*
|
|
629
|
+
* @example
|
|
630
|
+
* ```typescript
|
|
631
|
+
* import { v } from "convex/values";
|
|
632
|
+
* import { defineContentType, createContentSchema, createTypedCmsClient } from "@convex-cms/core";
|
|
633
|
+
* import { components } from "./_generated/api";
|
|
634
|
+
*
|
|
635
|
+
* // Define content types
|
|
636
|
+
* const blogPost = defineContentType({
|
|
637
|
+
* name: "blog_post",
|
|
638
|
+
* validator: v.object({
|
|
639
|
+
* title: v.string(),
|
|
640
|
+
* content: v.string(),
|
|
641
|
+
* }),
|
|
642
|
+
* meta: { displayName: "Blog Post" },
|
|
643
|
+
* });
|
|
644
|
+
*
|
|
645
|
+
* const contentSchema = createContentSchema({ blogPost });
|
|
646
|
+
*
|
|
647
|
+
* // Create a typed client
|
|
648
|
+
* export const cms = createTypedCmsClient(components.convexCms, {
|
|
649
|
+
* schema: contentSchema,
|
|
650
|
+
* });
|
|
651
|
+
*
|
|
652
|
+
* // Use with full type inference
|
|
653
|
+
* const post = await cms.typedContentEntries.get<"blog_post">(ctx, id);
|
|
654
|
+
* post.data.title; // ✅ string
|
|
655
|
+
* post.data.typo; // ❌ Error: Property 'typo' does not exist
|
|
656
|
+
* ```
|
|
657
|
+
*/
|
|
658
|
+
export function createTypedCmsClient<
|
|
659
|
+
TSchema extends ContentSchemaInstance<Record<string, ContentTypeDefinition>>
|
|
660
|
+
>(
|
|
661
|
+
componentApi: TypedComponentApi,
|
|
662
|
+
config: TypedCmsClientConfig<TSchema>,
|
|
663
|
+
): TypedCmsClient<TSchema> {
|
|
664
|
+
// Import createCmsClient dynamically to avoid circular imports
|
|
665
|
+
// The actual import happens at runtime
|
|
666
|
+
const { createCmsClient } = require("../index.js") as {
|
|
667
|
+
createCmsClient: (
|
|
668
|
+
api: TypedComponentApi,
|
|
669
|
+
config?: ComponentConfig,
|
|
670
|
+
) => CmsClient;
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
// Create the base client with the provided config
|
|
674
|
+
const baseClient = createCmsClient(componentApi, config);
|
|
675
|
+
|
|
676
|
+
// Create the typed content entries API
|
|
677
|
+
const typedContentEntries = new TypedContentEntriesApiImpl(
|
|
678
|
+
baseClient,
|
|
679
|
+
config.schema,
|
|
680
|
+
);
|
|
681
|
+
|
|
682
|
+
// Return an extended client with the typed API
|
|
683
|
+
return {
|
|
684
|
+
...baseClient,
|
|
685
|
+
schema: config.schema,
|
|
686
|
+
typedContentEntries,
|
|
687
|
+
};
|
|
688
|
+
}
|