@rakun-kit/core 1.4.6 → 1.4.7
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 +712 -684
- package/dist/cjs/api/utils/dynamicData.js +57 -11
- package/dist/cjs/api/utils/dynamicData.js.map +1 -1
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/dynamicData.js +7 -0
- package/dist/cjs/lib/dynamicData.js.map +1 -1
- package/dist/esm/api/context.d.ts +1 -1
- package/dist/esm/api/context.js +3 -3
- package/dist/esm/api/hooks/context.d.ts +1 -1
- package/dist/esm/api/hooks/runContentHooks.d.ts +4 -4
- package/dist/esm/api/hooks/runContentHooks.js +1 -1
- package/dist/esm/api/operations/catalog.d.ts +2 -2
- package/dist/esm/api/operations/catalog.js +1 -1
- package/dist/esm/api/operations/custom.d.ts +1 -1
- package/dist/esm/api/operations/custom.js +1 -1
- package/dist/esm/api/operations/index.d.ts +150 -150
- package/dist/esm/api/operations/index.js +8 -8
- package/dist/esm/api/operations/manager-contract.d.ts +118 -118
- package/dist/esm/api/operations/manager-contract.js +6 -6
- package/dist/esm/api/operations/manager.d.ts +119 -119
- package/dist/esm/api/operations/manager.js +57 -57
- package/dist/esm/api/operations/tracing.d.ts +1 -1
- package/dist/esm/api/operations/tracing.js +1 -1
- package/dist/esm/api/operations/types.d.ts +1 -1
- package/dist/esm/api/operations/web-contract.d.ts +24 -24
- package/dist/esm/api/operations/web-contract.js +3 -3
- package/dist/esm/api/operations/web.d.ts +25 -25
- package/dist/esm/api/operations/web.js +9 -9
- package/dist/esm/api/routes/manager/apiOperations.d.ts +3 -3
- package/dist/esm/api/routes/manager/apiOperations.js +5 -5
- package/dist/esm/api/routes/manager/auth/accountInfo.d.ts +2 -2
- package/dist/esm/api/routes/manager/auth/accountInfo.js +3 -3
- package/dist/esm/api/routes/manager/auth/deleteSession.d.ts +2 -2
- package/dist/esm/api/routes/manager/auth/deleteSession.js +3 -3
- package/dist/esm/api/routes/manager/auth/getSession.d.ts +7 -7
- package/dist/esm/api/routes/manager/auth/login.d.ts +2 -2
- package/dist/esm/api/routes/manager/auth/login.js +6 -6
- package/dist/esm/api/routes/manager/auth/logout.d.ts +1 -1
- package/dist/esm/api/routes/manager/auth/logout.js +3 -3
- package/dist/esm/api/routes/manager/auth/markTourSeen.d.ts +8 -8
- package/dist/esm/api/routes/manager/auth/markTourSeen.js +3 -3
- package/dist/esm/api/routes/manager/auth/totp/confirmTotp.d.ts +2 -2
- package/dist/esm/api/routes/manager/auth/totp/confirmTotp.js +2 -2
- package/dist/esm/api/routes/manager/auth/totp/enrollTotp.d.ts +1 -1
- package/dist/esm/api/routes/manager/auth/totp/enrollTotp.js +3 -3
- package/dist/esm/api/routes/manager/auth/totp/verifyTotp.d.ts +1 -1
- package/dist/esm/api/routes/manager/auth/totp/verifyTotp.js +5 -5
- package/dist/esm/api/routes/manager/auth/updateAccount.d.ts +8 -8
- package/dist/esm/api/routes/manager/auth/updateAccount.js +3 -3
- package/dist/esm/api/routes/manager/auth/updatePassword.d.ts +2 -2
- package/dist/esm/api/routes/manager/auth/updatePassword.js +5 -5
- package/dist/esm/api/routes/manager/auth/updateTutorialPreferences.d.ts +8 -8
- package/dist/esm/api/routes/manager/auth/updateTutorialPreferences.js +3 -3
- package/dist/esm/api/routes/manager/auth/webauthn/webauthnAuthOptions.js +4 -4
- package/dist/esm/api/routes/manager/auth/webauthn/webauthnAuthVerify.js +6 -6
- package/dist/esm/api/routes/manager/auth/webauthn/webauthnRegisterOptions.d.ts +2 -2
- package/dist/esm/api/routes/manager/auth/webauthn/webauthnRegisterOptions.js +3 -3
- package/dist/esm/api/routes/manager/auth/webauthn/webauthnRegisterVerify.d.ts +1 -1
- package/dist/esm/api/routes/manager/auth/webauthn/webauthnRegisterVerify.js +4 -4
- package/dist/esm/api/routes/manager/backups/create.d.ts +2 -2
- package/dist/esm/api/routes/manager/backups/create.js +2 -2
- package/dist/esm/api/routes/manager/backups/list.d.ts +2 -2
- package/dist/esm/api/routes/manager/backups/list.js +2 -2
- package/dist/esm/api/routes/manager/backups/restore.d.ts +2 -2
- package/dist/esm/api/routes/manager/backups/restore.js +4 -4
- package/dist/esm/api/routes/manager/comments.d.ts +2 -2
- package/dist/esm/api/routes/manager/comments.js +6 -6
- package/dist/esm/api/routes/manager/contentType.d.ts +10 -10
- package/dist/esm/api/routes/manager/contentType.js +3 -3
- package/dist/esm/api/routes/manager/contentTypes.d.ts +8 -8
- package/dist/esm/api/routes/manager/contentTypes.js +1 -1
- package/dist/esm/api/routes/manager/create.d.ts +5 -5
- package/dist/esm/api/routes/manager/create.js +13 -13
- package/dist/esm/api/routes/manager/delete.d.ts +2 -2
- package/dist/esm/api/routes/manager/delete.js +10 -10
- package/dist/esm/api/routes/manager/duplicate.d.ts +5 -5
- package/dist/esm/api/routes/manager/duplicate.js +6 -6
- package/dist/esm/api/routes/manager/favorites.d.ts +2 -2
- package/dist/esm/api/routes/manager/favorites.js +5 -5
- package/dist/esm/api/routes/manager/get.d.ts +2 -2
- package/dist/esm/api/routes/manager/get.js +11 -11
- package/dist/esm/api/routes/manager/languages.d.ts +4 -4
- package/dist/esm/api/routes/manager/languages.js +1 -1
- package/dist/esm/api/routes/manager/linkedIterator.d.ts +3 -3
- package/dist/esm/api/routes/manager/linkedIterator.js +8 -8
- package/dist/esm/api/routes/manager/list.d.ts +2 -2
- package/dist/esm/api/routes/manager/list.js +14 -14
- package/dist/esm/api/routes/manager/literals/list.d.ts +2 -2
- package/dist/esm/api/routes/manager/literals/list.js +5 -5
- package/dist/esm/api/routes/manager/literals/upsert.d.ts +2 -2
- package/dist/esm/api/routes/manager/literals/upsert.js +6 -6
- package/dist/esm/api/routes/manager/localeVariants.d.ts +18 -18
- package/dist/esm/api/routes/manager/localeVariants.js +15 -15
- package/dist/esm/api/routes/manager/media/createFolder.d.ts +2 -2
- package/dist/esm/api/routes/manager/media/createFolder.js +7 -7
- package/dist/esm/api/routes/manager/media/deleteFolder.d.ts +2 -2
- package/dist/esm/api/routes/manager/media/deleteFolder.js +7 -7
- package/dist/esm/api/routes/manager/media/deleteMediaStorage.js +2 -2
- package/dist/esm/api/routes/manager/media/finalizeUpload.d.ts +2 -2
- package/dist/esm/api/routes/manager/media/finalizeUpload.js +11 -11
- package/dist/esm/api/routes/manager/media/getMediaUrl.d.ts +2 -2
- package/dist/esm/api/routes/manager/media/getMediaUrl.js +6 -6
- package/dist/esm/api/routes/manager/media/listFolders.d.ts +2 -2
- package/dist/esm/api/routes/manager/media/listFolders.js +4 -4
- package/dist/esm/api/routes/manager/media/prepareUpload.d.ts +3 -3
- package/dist/esm/api/routes/manager/media/prepareUpload.js +5 -5
- package/dist/esm/api/routes/manager/media/resolveMediaRecordUrls.js +1 -1
- package/dist/esm/api/routes/manager/media/uploadBinary.d.ts +1 -1
- package/dist/esm/api/routes/manager/media/uploadBinary.js +7 -7
- package/dist/esm/api/routes/manager/migrations/list.d.ts +2 -2
- package/dist/esm/api/routes/manager/migrations/list.js +2 -2
- package/dist/esm/api/routes/manager/permissions.d.ts +1 -1
- package/dist/esm/api/routes/manager/permissions.js +2 -2
- package/dist/esm/api/routes/manager/preview/create.d.ts +2 -2
- package/dist/esm/api/routes/manager/preview/create.js +14 -14
- package/dist/esm/api/routes/manager/regenerateRoutes.d.ts +1 -1
- package/dist/esm/api/routes/manager/regenerateRoutes.js +2 -2
- package/dist/esm/api/routes/manager/setDefaultLanguage.d.ts +2 -2
- package/dist/esm/api/routes/manager/setDefaultLanguage.js +5 -5
- package/dist/esm/api/routes/manager/translateDocument.d.ts +2 -2
- package/dist/esm/api/routes/manager/translateDocument.js +13 -13
- package/dist/esm/api/routes/manager/trash.d.ts +2 -2
- package/dist/esm/api/routes/manager/trash.js +8 -8
- package/dist/esm/api/routes/manager/update.d.ts +5 -5
- package/dist/esm/api/routes/manager/update.js +12 -12
- package/dist/esm/api/routes/manager/users.d.ts +2 -2
- package/dist/esm/api/routes/manager/users.js +2 -2
- package/dist/esm/api/routes/manager/versions/get.d.ts +2 -2
- package/dist/esm/api/routes/manager/versions/get.js +2 -2
- package/dist/esm/api/routes/manager/versions/list.d.ts +2 -2
- package/dist/esm/api/routes/manager/versions/list.js +2 -2
- package/dist/esm/api/routes/manager/versions/restore.d.ts +2 -2
- package/dist/esm/api/routes/manager/versions/restore.js +4 -4
- package/dist/esm/api/routes/web/page.d.ts +4 -4
- package/dist/esm/api/routes/web/page.js +18 -18
- package/dist/esm/api/routes/web/previewPage.d.ts +8 -8
- package/dist/esm/api/routes/web/previewPage.js +9 -9
- package/dist/esm/api/routes/web/robots.d.ts +1 -1
- package/dist/esm/api/routes/web/robots.js +2 -2
- package/dist/esm/api/routes/web/seo.d.ts +1 -1
- package/dist/esm/api/routes/web/sitemap.d.ts +1 -1
- package/dist/esm/api/routes/web/sitemap.js +3 -3
- package/dist/esm/api/sessionCookie.d.ts +1 -1
- package/dist/esm/api/utils/authRateLimit.d.ts +1 -1
- package/dist/esm/api/utils/authRateLimit.js +1 -1
- package/dist/esm/api/utils/checkFailureCase.d.ts +1 -1
- package/dist/esm/api/utils/checkFailureCase.js +1 -1
- package/dist/esm/api/utils/checkOwnership.d.ts +2 -2
- package/dist/esm/api/utils/checkOwnership.js +5 -5
- package/dist/esm/api/utils/checkPermissions.d.ts +2 -2
- package/dist/esm/api/utils/checkPermissions.js +3 -3
- package/dist/esm/api/utils/dynamicData.d.ts +5 -5
- package/dist/esm/api/utils/dynamicData.d.ts.map +1 -1
- package/dist/esm/api/utils/dynamicData.js +66 -20
- package/dist/esm/api/utils/dynamicData.js.map +1 -1
- package/dist/esm/api/utils/getLanguages.d.ts +2 -2
- package/dist/esm/api/utils/getLanguages.js +2 -2
- package/dist/esm/api/utils/getLink.d.ts +2 -2
- package/dist/esm/api/utils/getLink.js +5 -5
- package/dist/esm/api/utils/getUser.d.ts +7 -7
- package/dist/esm/api/utils/getUser.js +4 -4
- package/dist/esm/api/utils/index.d.ts +24 -24
- package/dist/esm/api/utils/index.js +24 -24
- package/dist/esm/api/utils/linkedIterator.d.ts +3 -3
- package/dist/esm/api/utils/linkedIterator.js +7 -7
- package/dist/esm/api/utils/localeVariants.d.ts +1 -1
- package/dist/esm/api/utils/localeVariants.js +5 -5
- package/dist/esm/api/utils/mediaUploadToken.d.ts +1 -1
- package/dist/esm/api/utils/parseId.d.ts +1 -1
- package/dist/esm/api/utils/parseId.js +1 -1
- package/dist/esm/api/utils/passwords.js +1 -1
- package/dist/esm/api/utils/populates/populateLinks.d.ts +2 -2
- package/dist/esm/api/utils/populates/populateLinks.js +4 -4
- package/dist/esm/api/utils/populates/populateRelations.d.ts +2 -2
- package/dist/esm/api/utils/populates/populateRelations.js +6 -6
- package/dist/esm/api/utils/redirects/resolveRedirect.js +2 -2
- package/dist/esm/api/utils/requireContentType.d.ts +1 -1
- package/dist/esm/api/utils/requireContentType.js +2 -2
- package/dist/esm/api/utils/routes/revalidatePath.js +5 -5
- package/dist/esm/api/utils/routes/routeDefinitions.d.ts +1 -1
- package/dist/esm/api/utils/routes/routeMapHelpers.d.ts +6 -6
- package/dist/esm/api/utils/routes/routeMapHelpers.js +8 -8
- package/dist/esm/api/utils/routes/syncConfiguredRoutes.d.ts +2 -2
- package/dist/esm/api/utils/routes/syncConfiguredRoutes.js +5 -5
- package/dist/esm/api/utils/routes/updateRoutesMap.d.ts +2 -2
- package/dist/esm/api/utils/routes/updateRoutesMap.js +5 -5
- package/dist/esm/api/utils/safeManagerQuery.d.ts +2 -2
- package/dist/esm/api/utils/safeManagerQuery.js +1 -1
- package/dist/esm/api/utils/sanitizeManagerOutput.d.ts +1 -1
- package/dist/esm/api/utils/sanitizeManagerOutput.js +1 -1
- package/dist/esm/api/utils/transformObjectIdsToStrings.js +1 -1
- package/dist/esm/api/utils/transformStringToObjectIds.js +1 -1
- package/dist/esm/api/utils/translate.d.ts +1 -1
- package/dist/esm/api/utils/translate.js +3 -3
- package/dist/esm/api/utils/validateModule.d.ts +1 -1
- package/dist/esm/api/utils/validateModule.js +2 -2
- package/dist/esm/bootstrapState.d.ts +9 -9
- package/dist/esm/client.d.ts +51 -51
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +30 -30
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/contracts.d.ts +43 -43
- package/dist/esm/contracts.js +43 -43
- package/dist/esm/index.d.ts +41 -41
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +42 -42
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal-content-types/ApiOperation.d.ts +114 -114
- package/dist/esm/internal-content-types/ApiOperation.js +2 -2
- package/dist/esm/internal-content-types/Backup.d.ts +57 -57
- package/dist/esm/internal-content-types/Backup.d.ts.map +1 -1
- package/dist/esm/internal-content-types/Backup.js +2 -2
- package/dist/esm/internal-content-types/BackupDocument.d.ts +114 -114
- package/dist/esm/internal-content-types/BackupDocument.js +2 -2
- package/dist/esm/internal-content-types/ContentComment.d.ts +788 -788
- package/dist/esm/internal-content-types/ContentComment.js +3 -3
- package/dist/esm/internal-content-types/ContentVersion.d.ts +139 -139
- package/dist/esm/internal-content-types/ContentVersion.d.ts.map +1 -1
- package/dist/esm/internal-content-types/ContentVersion.js +2 -2
- package/dist/esm/internal-content-types/HelloWorld.d.ts +30 -30
- package/dist/esm/internal-content-types/HelloWorld.js +2 -2
- package/dist/esm/internal-content-types/Language.d.ts +39 -39
- package/dist/esm/internal-content-types/Language.js +2 -2
- package/dist/esm/internal-content-types/LinkedIteratorTemplate.d.ts +79 -79
- package/dist/esm/internal-content-types/LinkedIteratorTemplate.d.ts.map +1 -1
- package/dist/esm/internal-content-types/LinkedIteratorTemplate.js +2 -2
- package/dist/esm/internal-content-types/LiteralTranslation.d.ts +59 -59
- package/dist/esm/internal-content-types/LiteralTranslation.js +2 -2
- package/dist/esm/internal-content-types/ManagerFavorite.d.ts +547 -547
- package/dist/esm/internal-content-types/ManagerFavorite.js +3 -3
- package/dist/esm/internal-content-types/ManagerRole.d.ts +33 -33
- package/dist/esm/internal-content-types/ManagerRole.js +2 -2
- package/dist/esm/internal-content-types/ManagerRoleHooks.d.ts +2 -2
- package/dist/esm/internal-content-types/ManagerRoleHooks.js +3 -3
- package/dist/esm/internal-content-types/ManagerUser.d.ts +212 -212
- package/dist/esm/internal-content-types/ManagerUser.js +3 -3
- package/dist/esm/internal-content-types/ManagerUserHooks.d.ts +2 -2
- package/dist/esm/internal-content-types/ManagerUserHooks.js +3 -3
- package/dist/esm/internal-content-types/Media.d.ts +261 -261
- package/dist/esm/internal-content-types/Media.js +3 -3
- package/dist/esm/internal-content-types/MediaFolder.d.ts +88 -88
- package/dist/esm/internal-content-types/MediaFolder.js +2 -2
- package/dist/esm/internal-content-types/MfaChallenge.d.ts +570 -570
- package/dist/esm/internal-content-types/MfaChallenge.d.ts.map +1 -1
- package/dist/esm/internal-content-types/MfaChallenge.js +3 -3
- package/dist/esm/internal-content-types/Migration.d.ts +133 -133
- package/dist/esm/internal-content-types/Migration.d.ts.map +1 -1
- package/dist/esm/internal-content-types/Migration.js +2 -2
- package/dist/esm/internal-content-types/MigrationLock.d.ts +16 -16
- package/dist/esm/internal-content-types/MigrationLock.js +2 -2
- package/dist/esm/internal-content-types/Page.d.ts +85 -85
- package/dist/esm/internal-content-types/Page.js +3 -3
- package/dist/esm/internal-content-types/PreviewSnapshot.d.ts +213 -213
- package/dist/esm/internal-content-types/PreviewSnapshot.js +2 -2
- package/dist/esm/internal-content-types/Redirect.d.ts +146 -146
- package/dist/esm/internal-content-types/Redirect.js +2 -2
- package/dist/esm/internal-content-types/RobotsRule.d.ts +103 -103
- package/dist/esm/internal-content-types/RobotsRule.d.ts.map +1 -1
- package/dist/esm/internal-content-types/RobotsRule.js +2 -2
- package/dist/esm/internal-content-types/Route.d.ts +123 -123
- package/dist/esm/internal-content-types/Route.d.ts.map +1 -1
- package/dist/esm/internal-content-types/Route.js +2 -2
- package/dist/esm/internal-content-types/RouteLayoutModule.d.ts +164 -164
- package/dist/esm/internal-content-types/RouteLayoutModule.d.ts.map +1 -1
- package/dist/esm/internal-content-types/RouteLayoutModule.js +2 -2
- package/dist/esm/internal-content-types/RouteLayoutModuleOverride.d.ts +143 -143
- package/dist/esm/internal-content-types/RouteLayoutModuleOverride.js +2 -2
- package/dist/esm/internal-content-types/RouteLocaleVariant.d.ts +170 -170
- package/dist/esm/internal-content-types/RouteLocaleVariant.js +2 -2
- package/dist/esm/internal-content-types/RouteMap.d.ts +144 -144
- package/dist/esm/internal-content-types/RouteMap.js +2 -2
- package/dist/esm/internal-content-types/RouteSettings.d.ts +116 -116
- package/dist/esm/internal-content-types/RouteSettings.js +3 -3
- package/dist/esm/internal-content-types/SchemaState.d.ts +65 -65
- package/dist/esm/internal-content-types/SchemaState.d.ts.map +1 -1
- package/dist/esm/internal-content-types/SchemaState.js +2 -2
- package/dist/esm/internal-content-types/Seo.d.ts +430 -430
- package/dist/esm/internal-content-types/Seo.js +2 -2
- package/dist/esm/internal-content-types/SeoSettings.d.ts +518 -518
- package/dist/esm/internal-content-types/SeoSettings.js +3 -3
- package/dist/esm/internal-content-types/Session.d.ts +533 -533
- package/dist/esm/internal-content-types/Session.js +3 -3
- package/dist/esm/internal-content-types/UserMfa.d.ts +502 -502
- package/dist/esm/internal-content-types/UserMfa.js +3 -3
- package/dist/esm/internal-content-types/WebAuthnCredential.d.ts +624 -624
- package/dist/esm/internal-content-types/WebAuthnCredential.d.ts.map +1 -1
- package/dist/esm/internal-content-types/WebAuthnCredential.js +3 -3
- package/dist/esm/internal-content-types/WebAuthnRegChallenge.d.ts +562 -562
- package/dist/esm/internal-content-types/WebAuthnRegChallenge.js +3 -3
- package/dist/esm/internal-content-types/index.d.ts +34 -34
- package/dist/esm/internal-content-types/index.js +34 -34
- package/dist/esm/internal-content-types/syncAdminRole.d.ts +4 -4
- package/dist/esm/internal-content-types/syncAdminRole.js +4 -4
- package/dist/esm/lib/ContentType.d.ts +7 -7
- package/dist/esm/lib/ContentType.js +5 -5
- package/dist/esm/lib/Permissions.d.ts +2 -2
- package/dist/esm/lib/Permissions.js +3 -3
- package/dist/esm/lib/Registry.d.ts +6 -6
- package/dist/esm/lib/Registry.js +1 -1
- package/dist/esm/lib/dynamicData.d.ts +19 -0
- package/dist/esm/lib/dynamicData.d.ts.map +1 -1
- package/dist/esm/lib/dynamicData.js +7 -0
- package/dist/esm/lib/dynamicData.js.map +1 -1
- package/dist/esm/lib/errors/AppError.d.ts +1 -1
- package/dist/esm/lib/errors/AppError.js +1 -1
- package/dist/esm/lib/errors/index.d.ts +4 -4
- package/dist/esm/lib/errors/index.js +3 -3
- package/dist/esm/lib/errors/throwAppError.d.ts +1 -1
- package/dist/esm/lib/errors/throwAppError.js +3 -3
- package/dist/esm/lib/fields/Boolean.d.ts +1 -1
- package/dist/esm/lib/fields/Boolean.js +1 -1
- package/dist/esm/lib/fields/ContentReference.d.ts +2 -2
- package/dist/esm/lib/fields/ContentReference.js +2 -2
- package/dist/esm/lib/fields/Date.d.ts +1 -1
- package/dist/esm/lib/fields/Date.js +1 -1
- package/dist/esm/lib/fields/Field.d.ts +12 -12
- package/dist/esm/lib/fields/Fields.d.ts +13 -13
- package/dist/esm/lib/fields/Fields.js +13 -13
- package/dist/esm/lib/fields/File.d.ts +1 -1
- package/dist/esm/lib/fields/File.js +2 -2
- package/dist/esm/lib/fields/Iterator.d.ts +2 -2
- package/dist/esm/lib/fields/Iterator.js +3 -3
- package/dist/esm/lib/fields/Link.d.ts +1 -1
- package/dist/esm/lib/fields/Link.js +2 -2
- package/dist/esm/lib/fields/List.d.ts +1 -1
- package/dist/esm/lib/fields/List.js +2 -2
- package/dist/esm/lib/fields/Number.d.ts +1 -1
- package/dist/esm/lib/fields/Number.js +1 -1
- package/dist/esm/lib/fields/Relation.d.ts +3 -3
- package/dist/esm/lib/fields/Relation.js +3 -3
- package/dist/esm/lib/fields/Select.d.ts +1 -1
- package/dist/esm/lib/fields/Select.js +1 -1
- package/dist/esm/lib/fields/SelfRelation.d.ts +1 -1
- package/dist/esm/lib/fields/SelfRelation.js +2 -2
- package/dist/esm/lib/fields/SimpleList.d.ts +1 -1
- package/dist/esm/lib/fields/SimpleList.js +1 -1
- package/dist/esm/lib/fields/String.d.ts +1 -1
- package/dist/esm/lib/fields/String.js +3 -3
- package/dist/esm/lib/fields/index.d.ts +15 -15
- package/dist/esm/lib/fields/index.js +15 -15
- package/dist/esm/lib/hooks.d.ts +3 -3
- package/dist/esm/lib/routeableContent.js +1 -1
- package/dist/esm/lib/types/index.d.ts +2 -2
- package/dist/esm/lib/utils/getListField.d.ts +1 -1
- package/dist/esm/lib/utils/getSchemas.d.ts +1 -1
- package/dist/esm/lib/utils/getTranslation.d.ts +2 -2
- package/dist/esm/lib/utils/getTranslation.js +1 -1
- package/dist/esm/lib/utils/isTranslatableObject.d.ts +1 -1
- package/dist/esm/lib/utils/translateObject.d.ts +2 -2
- package/dist/esm/lib/utils/translateObject.js +3 -3
- package/dist/esm/literals/definitions.d.ts +1 -1
- package/dist/esm/literals/definitions.js +1 -1
- package/dist/esm/literals/index.d.ts +3 -3
- package/dist/esm/literals/index.js +3 -3
- package/dist/esm/literals/manager.d.ts +1 -1
- package/dist/esm/literals/manager.js +1 -1
- package/dist/esm/manager.d.ts +3 -3
- package/dist/esm/manager.js +1 -1
- package/dist/esm/media/imageOptimization.d.ts +1 -1
- package/dist/esm/media/imageOptimization.js +2 -2
- package/dist/esm/media/index.d.ts +4 -4
- package/dist/esm/media/index.js +3 -3
- package/dist/esm/media/mediaService.d.ts +1 -1
- package/dist/esm/orm/backups.js +5 -5
- package/dist/esm/orm/createIndexes.js +3 -3
- package/dist/esm/orm/database.js +3 -3
- package/dist/esm/orm/dbService.d.ts +6 -6
- package/dist/esm/orm/index.d.ts +2 -2
- package/dist/esm/orm/index.js +16 -16
- package/dist/esm/orm/migrations.d.ts +1 -1
- package/dist/esm/orm/migrations.js +4 -4
- package/dist/esm/orm/mongodbPeer.js +1 -1
- package/dist/esm/orm/operations/clear.d.ts +2 -2
- package/dist/esm/orm/operations/clear.js +1 -1
- package/dist/esm/orm/operations/create.d.ts +4 -4
- package/dist/esm/orm/operations/create.js +7 -7
- package/dist/esm/orm/operations/delete.d.ts +3 -3
- package/dist/esm/orm/operations/delete.js +5 -5
- package/dist/esm/orm/operations/find.d.ts +2 -2
- package/dist/esm/orm/operations/find.js +3 -3
- package/dist/esm/orm/operations/findDependencies.d.ts +2 -2
- package/dist/esm/orm/operations/findDependencies.js +4 -4
- package/dist/esm/orm/operations/get.d.ts +3 -3
- package/dist/esm/orm/operations/get.js +3 -3
- package/dist/esm/orm/operations/getAll.d.ts +2 -2
- package/dist/esm/orm/operations/getAll.js +2 -2
- package/dist/esm/orm/operations/list.d.ts +2 -2
- package/dist/esm/orm/operations/list.js +3 -3
- package/dist/esm/orm/operations/update.d.ts +5 -5
- package/dist/esm/orm/operations/update.js +8 -8
- package/dist/esm/orm/operations/updateMany.d.ts +4 -4
- package/dist/esm/orm/operations/updateMany.js +4 -4
- package/dist/esm/orm/operations/upsert.d.ts +3 -3
- package/dist/esm/orm/operations/upsert.js +4 -4
- package/dist/esm/orm/utils/deepDeleteNulls.js +1 -1
- package/dist/esm/orm/utils/parseId.d.ts +1 -1
- package/dist/esm/orm/utils/parseId.js +1 -1
- package/dist/esm/orm/utils/transformObjectIdsToStrings.js +1 -1
- package/dist/esm/orm/utils/transformStringToObjectIds.js +1 -1
- package/dist/esm/orm/versions.d.ts +1 -1
- package/dist/esm/orm/versions.js +7 -7
- package/dist/esm/plugins.d.ts +9 -9
- package/dist/esm/schemas/manager/comments.js +1 -1
- package/dist/esm/schemas/manager/create.js +1 -1
- package/dist/esm/schemas/manager/literals/upsert.js +1 -1
- package/dist/esm/schemas/manager/localeVariants.d.ts +96 -96
- package/dist/esm/schemas/manager/localeVariants.js +1 -1
- package/dist/esm/schemas/manager/media/finalizeUpload.js +1 -1
- package/dist/esm/schemas/manager/media/getMediaUrl.js +1 -1
- package/dist/esm/schemas/manager/media/listFolders.js +1 -1
- package/dist/esm/schemas/manager/update.js +1 -1
- package/dist/esm/schemas/web/page.d.ts +40 -40
- package/dist/esm/schemas/web/page.js +1 -1
- package/dist/esm/schemas/web/previewPage.d.ts +28 -28
- package/dist/esm/schemas/web/previewPage.js +1 -1
- package/dist/esm/translation/document.d.ts +3 -3
- package/dist/esm/translation/index.d.ts +4 -4
- package/dist/esm/translation/index.js +3 -3
- package/dist/esm/translation/translationService.d.ts +1 -1
- package/dist/esm/web/client.d.ts +1 -1
- package/dist/esm/web/client.js +1 -1
- package/dist/esm/web/index.d.ts +2 -2
- package/dist/esm/web/index.js +2 -2
- package/dist/esm/web/page.d.ts +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +131 -131
package/README.md
CHANGED
|
@@ -1,686 +1,714 @@
|
|
|
1
|
-
# @rakun-kit/core
|
|
2
|
-
|
|
3
|
-
`@rakun-kit/core` contains Rakun's shared domain model and runtime. It defines content types, fields, Zod schemas, manager/web operations, request context, MongoDB connection handling, media service, permissions, translations, and typed contracts used by adapters (`@rakun-kit/next`, `@rakun-kit/express`, `@rakun-kit/trpc`) and the manager client.
|
|
4
|
-
|
|
5
|
-
## Main Entry
|
|
6
|
-
|
|
7
|
-
Typical imports:
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
import {
|
|
11
|
-
ContentType,
|
|
12
|
-
Fields,
|
|
13
|
-
rakunBootstrap,
|
|
14
|
-
ensureRakunInitialized,
|
|
15
|
-
} from "@rakun-kit/core";
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
The main entrypoint exports:
|
|
19
|
-
|
|
20
|
-
- Bootstrap: `rakunBootstrap`, `ensureRakunBootstrap`, `ensureRakunInitialized`, `getRakunBootstrapOptions`.
|
|
21
|
-
- Context: `createRequestContext`, `getSessionCookie`, `setSessionCookie`.
|
|
22
|
-
- Operations: manager/web contracts and definitions.
|
|
23
|
-
- Media: `createMediaService`, `getMediaService`, adapters, and types.
|
|
24
|
-
- Permissions, translations, errors, contracts, and public types.
|
|
25
|
-
- Basic internal content types: `Language`, `ManagerUser`, `Seo`.
|
|
26
|
-
|
|
27
|
-
Relevant subpaths:
|
|
28
|
-
|
|
29
|
-
- `@rakun-kit/core/manager`: manager operation metadata and types.
|
|
30
|
-
- `@rakun-kit/core/contracts`: shared manager/web payload schemas.
|
|
31
|
-
- `@rakun-kit/core/client`: client-facing types and utilities.
|
|
32
|
-
- `@rakun-kit/core/logger`: logger.
|
|
33
|
-
- `@rakun-kit/core/errors`: application errors.
|
|
34
|
-
- `@rakun-kit/core/types`: types derived from content types.
|
|
35
|
-
|
|
36
|
-
## Bootstrap
|
|
37
|
-
|
|
38
|
-
`rakunBootstrap(options)` registers global configuration and content types:
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
rakunBootstrap({
|
|
42
|
-
literals,
|
|
43
|
-
contentTypes: [Page, Post],
|
|
44
|
-
routes,
|
|
45
|
-
apiOperations,
|
|
46
|
-
mongo: {
|
|
47
|
-
MONGO_URI: process.env.MONGO_URI!,
|
|
48
|
-
ENVIRONMENT: process.env.NODE_ENV === "test" ? "test" : "production",
|
|
49
|
-
},
|
|
50
|
-
media,
|
|
51
|
-
logger: {
|
|
52
|
-
level: "info",
|
|
53
|
-
prettify: true,
|
|
54
|
-
},
|
|
55
|
-
syncRoutes: true,
|
|
56
|
-
});
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Options:
|
|
60
|
-
|
|
61
|
-
- `literals`: text/translation catalog.
|
|
62
|
-
- `contentTypes`: application content types.
|
|
63
|
-
- `internalContentTypes`: optional overrides for Rakun internal content types, currently `Page`.
|
|
64
|
-
- `routes`: configured routes used to resolve pages.
|
|
65
|
-
- `apiOperations`: custom API operations added to the Rakun operation registry.
|
|
66
|
-
- `mongo`: MongoDB connection. Required before serving Rakun requests.
|
|
67
|
-
- `media`: media adapter/configuration. Optional.
|
|
68
|
-
- `logger`: logger configuration. If omitted, an `info` logger with `prettify` is created.
|
|
69
|
-
- `syncRoutes`: syncs configured routes during initialization. Enabled by default.
|
|
70
|
-
|
|
71
|
-
Content types can define lifecycle `hooks` and opt into manager-selected
|
|
72
|
-
`dynamicData` sources.
|
|
73
|
-
|
|
74
|
-
Routes can define fixed layout module slots. Rakun syncs those slots and the
|
|
75
|
-
manager lets users select an existing entry for each route:
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
rakunBootstrap({
|
|
79
|
-
// ...
|
|
80
|
-
routes: [
|
|
81
|
-
{
|
|
82
|
-
key: "pages",
|
|
83
|
-
contentType: "Page",
|
|
84
|
-
field: "slug",
|
|
85
|
-
hasPage: true,
|
|
86
|
-
dynamic: false,
|
|
87
|
-
defaultBasePath: "",
|
|
88
|
-
layout: [
|
|
89
|
-
{ key: "header", contentType: "Header" },
|
|
90
|
-
{ type: "content" },
|
|
91
|
-
{ key: "footer", contentType: "Footer" },
|
|
92
|
-
],
|
|
93
|
-
},
|
|
94
|
-
],
|
|
95
|
-
});
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
The web page response includes an ordered `layout` array containing module slots
|
|
99
|
-
plus the content slot.
|
|
100
|
-
|
|
101
|
-
`ensureRakunInitialized()` prepares logger, MongoDB, media, and route syncing. It uses a singleton promise to avoid concurrent initialization; if initialization fails, the promise is cleared so the next call can retry.
|
|
102
|
-
|
|
103
|
-
`ensureRakunBootstrap(options)` only calls `rakunBootstrap` if the runtime has not been bootstrapped yet.
|
|
104
|
-
|
|
105
|
-
## Plugins
|
|
106
|
-
|
|
107
|
-
Trusted server plugins contribute to the same bootstrap registry without coupling
|
|
108
|
-
core to React:
|
|
109
|
-
|
|
110
|
-
```ts
|
|
111
|
-
import { defineRakunPlugin, rakunBootstrap } from '@rakun-kit/core'
|
|
112
|
-
|
|
113
|
-
export const analyticsPlugin = defineRakunPlugin({
|
|
114
|
-
id: '@acme/rakun-analytics',
|
|
115
|
-
contentTypes: [AnalyticsEvent],
|
|
116
|
-
routes: analyticsRoutes,
|
|
117
|
-
apiOperations: analyticsOperations,
|
|
118
|
-
permissions: ['plugin.analytics.view'],
|
|
119
|
-
literals: {},
|
|
120
|
-
initialize: async ({ db }) => {
|
|
121
|
-
// Services and migrations are ready here. Keep initialization idempotent.
|
|
122
|
-
},
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
rakunBootstrap({
|
|
126
|
-
plugins: [analyticsPlugin],
|
|
127
|
-
contentTypes: [],
|
|
128
|
-
literals: {},
|
|
129
|
-
mongo,
|
|
130
|
-
})
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Plugin ids and contributed content types, routes, operations, literals, and
|
|
134
|
-
custom field editor ids must be unique. Rakun reports both owners on conflicts.
|
|
135
|
-
Visual manager and web facets are registered separately in their browser
|
|
136
|
-
runtimes.
|
|
137
|
-
|
|
138
|
-
Custom field factories can use `createPluginField`. Their serializable
|
|
139
|
-
`meta.editor` must match a field declaration in the server plugin and a React
|
|
140
|
-
editor registered by its manager facet.
|
|
141
|
-
|
|
142
|
-
## Content Types
|
|
143
|
-
|
|
144
|
-
A `ContentType` defines a logical collection:
|
|
145
|
-
|
|
146
|
-
```ts
|
|
147
|
-
const Post = new ContentType({
|
|
148
|
-
name: "Post",
|
|
149
|
-
comments: true,
|
|
150
|
-
menu: {
|
|
151
|
-
title: "Posts",
|
|
152
|
-
icon: "newspaper",
|
|
153
|
-
category: "Content",
|
|
154
|
-
},
|
|
155
|
-
fields: {
|
|
156
|
-
title: Fields.string().required(),
|
|
157
|
-
slug: Fields.string().type("Slug").required(),
|
|
158
|
-
body: Fields.string().type("RichText"),
|
|
159
|
-
published: Fields.boolean(),
|
|
160
|
-
},
|
|
161
|
-
uniques: [["slug"]],
|
|
162
|
-
listFields: ["title", "slug", "published"],
|
|
163
|
-
});
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Page-like content types can define ordered page modules with `iterator` outside
|
|
167
|
-
`fields`. Rakun persists this generated field as `_iterator`:
|
|
168
|
-
|
|
169
|
-
```ts
|
|
170
|
-
const Page = new ContentType({
|
|
171
|
-
name: "Page",
|
|
172
|
-
fields: {
|
|
173
|
-
title: Fields.string().required(),
|
|
174
|
-
slug: Fields.string().type("Slug").required(),
|
|
175
|
-
},
|
|
176
|
-
iterator: [{ contentType: PageSection, type: "existing" }],
|
|
177
|
-
linkedIterator: true,
|
|
178
|
-
});
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
Set `linkedIterator: true` when every document should use one shared module
|
|
182
|
-
structure. The manager stores a canonical iterator for the content type, while
|
|
183
|
-
dynamic bindings such as `Current document` continue to resolve against the
|
|
184
|
-
individual page being rendered. Documents are linked by default and can be
|
|
185
|
-
unlinked in the manager to keep a local copy of the iterator.
|
|
186
|
-
|
|
187
|
-
Main properties:
|
|
188
|
-
|
|
189
|
-
- `name`: stable type name. Also used as `_type`.
|
|
190
|
-
- `fields`: field map.
|
|
191
|
-
- `iterator`: page module entries. Generates the reserved `_iterator` field.
|
|
192
|
-
- `linkedIterator`: shares that iterator between documents while allowing
|
|
193
|
-
explicit per-document overrides.
|
|
194
|
-
- `menu`: manager metadata.
|
|
195
|
-
- `uniques`: unique field groups.
|
|
196
|
-
- `listFields`: preferred fields in lists and relations.
|
|
197
|
-
- `hideFromManager()`: hides the content type from manager content type lists.
|
|
198
|
-
- `apiOnly()`: applies `.apiOnly()` to every field in the content type.
|
|
199
|
-
- `managerOnly()`: applies `.managerOnly()` to every field in the content type.
|
|
200
|
-
- `comments: true` or `enableComments()`: enables manager document comments and user mentions for saved entries.
|
|
201
|
-
- `withHooks()`: attaches lifecycle hooks such as `beforeInsert`, `beforeUpdate`, and `onGet`.
|
|
202
|
-
- Dynamic data bindings are available on manager-visible fields by default; use
|
|
203
|
-
field-level `.noDynamic()` to opt out.
|
|
204
|
-
|
|
205
|
-
When a content type has a configured route with `hasPage: true`, Rakun also
|
|
206
|
-
adds an optional reserved `_seo` relation automatically.
|
|
207
|
-
|
|
208
|
-
Hooks run around DB mutations and public output resolution:
|
|
209
|
-
|
|
210
|
-
```ts
|
|
211
|
-
const User = new ContentType({
|
|
212
|
-
name: "User",
|
|
213
|
-
fields: {
|
|
214
|
-
email: Fields.string().type("Email").required(),
|
|
215
|
-
password: Fields.string().type("Password").required().managerOnly(),
|
|
216
|
-
},
|
|
217
|
-
}).withHooks({
|
|
218
|
-
beforeInsert: ({ data }) => ({
|
|
219
|
-
...data,
|
|
220
|
-
password: hashPassword(String(data.password)),
|
|
221
|
-
}),
|
|
222
|
-
onGet: ({ data }) => ({
|
|
223
|
-
...data,
|
|
224
|
-
displayName: String(data.email).split("@")[0],
|
|
225
|
-
}),
|
|
226
|
-
});
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
Dynamic data turns a content type into a reusable layout. The manager can bind
|
|
230
|
-
manager-visible fields to another content item field, or to a generated `href`
|
|
231
|
-
when a source content type has a page route. Fields are dynamic by default; call
|
|
232
|
-
`.noDynamic()` on fields that should not accept bindings or be exported as
|
|
233
|
-
source paths. Source content types are hidden by default; set
|
|
234
|
-
`dynamicDataSource: true` on content types that should appear in the manager
|
|
235
|
-
source selector. Field bindings can also select `Current document` to read values
|
|
236
|
-
from the document being edited without marking its content type as a source.
|
|
237
|
-
|
|
238
|
-
Source field selectors are type-aware. A string target only offers string-like
|
|
239
|
-
source paths, number targets only offer numbers, and boolean targets only offer
|
|
240
|
-
booleans. Object-like source fields are traversed so nested leaf fields can be
|
|
241
|
-
selected, while reserved SEO metadata is omitted from dynamic data mappings.
|
|
242
|
-
The generated `href` source is only shown for content types that have a
|
|
243
|
-
configured route with `hasPage: true`.
|
|
244
|
-
|
|
245
|
-
```ts
|
|
246
|
-
const Project = new ContentType({
|
|
247
|
-
name: "Project",
|
|
248
|
-
dynamicDataSource: true,
|
|
249
|
-
fields: {
|
|
250
|
-
title: Fields.string().required(),
|
|
251
|
-
slug: Fields.string().type("Slug").required(),
|
|
252
|
-
},
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
const Carousel = new ContentType({
|
|
256
|
-
name: "Carousel",
|
|
257
|
-
fields: {
|
|
258
|
-
title: Fields.string().required(),
|
|
259
|
-
internalNote: Fields.string().noDynamic(),
|
|
260
|
-
items: Fields.blocks([
|
|
261
|
-
{
|
|
262
|
-
name: "CarouselItem",
|
|
263
|
-
field: Fields.relation(CarouselItem, "new"),
|
|
264
|
-
},
|
|
265
|
-
]),
|
|
266
|
-
},
|
|
267
|
-
});
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
List bindings append dynamic items to manually stored items instead of replacing
|
|
271
|
-
the list. If the same stable item id appears in both sources, the dynamically
|
|
272
|
-
resolved item wins and the duplicate manual copy is skipped.
|
|
273
|
-
|
|
1
|
+
# @rakun-kit/core
|
|
2
|
+
|
|
3
|
+
`@rakun-kit/core` contains Rakun's shared domain model and runtime. It defines content types, fields, Zod schemas, manager/web operations, request context, MongoDB connection handling, media service, permissions, translations, and typed contracts used by adapters (`@rakun-kit/next`, `@rakun-kit/express`, `@rakun-kit/trpc`) and the manager client.
|
|
4
|
+
|
|
5
|
+
## Main Entry
|
|
6
|
+
|
|
7
|
+
Typical imports:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import {
|
|
11
|
+
ContentType,
|
|
12
|
+
Fields,
|
|
13
|
+
rakunBootstrap,
|
|
14
|
+
ensureRakunInitialized,
|
|
15
|
+
} from "@rakun-kit/core";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The main entrypoint exports:
|
|
19
|
+
|
|
20
|
+
- Bootstrap: `rakunBootstrap`, `ensureRakunBootstrap`, `ensureRakunInitialized`, `getRakunBootstrapOptions`.
|
|
21
|
+
- Context: `createRequestContext`, `getSessionCookie`, `setSessionCookie`.
|
|
22
|
+
- Operations: manager/web contracts and definitions.
|
|
23
|
+
- Media: `createMediaService`, `getMediaService`, adapters, and types.
|
|
24
|
+
- Permissions, translations, errors, contracts, and public types.
|
|
25
|
+
- Basic internal content types: `Language`, `ManagerUser`, `Seo`.
|
|
26
|
+
|
|
27
|
+
Relevant subpaths:
|
|
28
|
+
|
|
29
|
+
- `@rakun-kit/core/manager`: manager operation metadata and types.
|
|
30
|
+
- `@rakun-kit/core/contracts`: shared manager/web payload schemas.
|
|
31
|
+
- `@rakun-kit/core/client`: client-facing types and utilities.
|
|
32
|
+
- `@rakun-kit/core/logger`: logger.
|
|
33
|
+
- `@rakun-kit/core/errors`: application errors.
|
|
34
|
+
- `@rakun-kit/core/types`: types derived from content types.
|
|
35
|
+
|
|
36
|
+
## Bootstrap
|
|
37
|
+
|
|
38
|
+
`rakunBootstrap(options)` registers global configuration and content types:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
rakunBootstrap({
|
|
42
|
+
literals,
|
|
43
|
+
contentTypes: [Page, Post],
|
|
44
|
+
routes,
|
|
45
|
+
apiOperations,
|
|
46
|
+
mongo: {
|
|
47
|
+
MONGO_URI: process.env.MONGO_URI!,
|
|
48
|
+
ENVIRONMENT: process.env.NODE_ENV === "test" ? "test" : "production",
|
|
49
|
+
},
|
|
50
|
+
media,
|
|
51
|
+
logger: {
|
|
52
|
+
level: "info",
|
|
53
|
+
prettify: true,
|
|
54
|
+
},
|
|
55
|
+
syncRoutes: true,
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Options:
|
|
60
|
+
|
|
61
|
+
- `literals`: text/translation catalog.
|
|
62
|
+
- `contentTypes`: application content types.
|
|
63
|
+
- `internalContentTypes`: optional overrides for Rakun internal content types, currently `Page`.
|
|
64
|
+
- `routes`: configured routes used to resolve pages.
|
|
65
|
+
- `apiOperations`: custom API operations added to the Rakun operation registry.
|
|
66
|
+
- `mongo`: MongoDB connection. Required before serving Rakun requests.
|
|
67
|
+
- `media`: media adapter/configuration. Optional.
|
|
68
|
+
- `logger`: logger configuration. If omitted, an `info` logger with `prettify` is created.
|
|
69
|
+
- `syncRoutes`: syncs configured routes during initialization. Enabled by default.
|
|
70
|
+
|
|
71
|
+
Content types can define lifecycle `hooks` and opt into manager-selected
|
|
72
|
+
`dynamicData` sources.
|
|
73
|
+
|
|
74
|
+
Routes can define fixed layout module slots. Rakun syncs those slots and the
|
|
75
|
+
manager lets users select an existing entry for each route:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
rakunBootstrap({
|
|
79
|
+
// ...
|
|
80
|
+
routes: [
|
|
81
|
+
{
|
|
82
|
+
key: "pages",
|
|
83
|
+
contentType: "Page",
|
|
84
|
+
field: "slug",
|
|
85
|
+
hasPage: true,
|
|
86
|
+
dynamic: false,
|
|
87
|
+
defaultBasePath: "",
|
|
88
|
+
layout: [
|
|
89
|
+
{ key: "header", contentType: "Header" },
|
|
90
|
+
{ type: "content" },
|
|
91
|
+
{ key: "footer", contentType: "Footer" },
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The web page response includes an ordered `layout` array containing module slots
|
|
99
|
+
plus the content slot.
|
|
100
|
+
|
|
101
|
+
`ensureRakunInitialized()` prepares logger, MongoDB, media, and route syncing. It uses a singleton promise to avoid concurrent initialization; if initialization fails, the promise is cleared so the next call can retry.
|
|
102
|
+
|
|
103
|
+
`ensureRakunBootstrap(options)` only calls `rakunBootstrap` if the runtime has not been bootstrapped yet.
|
|
104
|
+
|
|
105
|
+
## Plugins
|
|
106
|
+
|
|
107
|
+
Trusted server plugins contribute to the same bootstrap registry without coupling
|
|
108
|
+
core to React:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { defineRakunPlugin, rakunBootstrap } from '@rakun-kit/core'
|
|
112
|
+
|
|
113
|
+
export const analyticsPlugin = defineRakunPlugin({
|
|
114
|
+
id: '@acme/rakun-analytics',
|
|
115
|
+
contentTypes: [AnalyticsEvent],
|
|
116
|
+
routes: analyticsRoutes,
|
|
117
|
+
apiOperations: analyticsOperations,
|
|
118
|
+
permissions: ['plugin.analytics.view'],
|
|
119
|
+
literals: {},
|
|
120
|
+
initialize: async ({ db }) => {
|
|
121
|
+
// Services and migrations are ready here. Keep initialization idempotent.
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
rakunBootstrap({
|
|
126
|
+
plugins: [analyticsPlugin],
|
|
127
|
+
contentTypes: [],
|
|
128
|
+
literals: {},
|
|
129
|
+
mongo,
|
|
130
|
+
})
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Plugin ids and contributed content types, routes, operations, literals, and
|
|
134
|
+
custom field editor ids must be unique. Rakun reports both owners on conflicts.
|
|
135
|
+
Visual manager and web facets are registered separately in their browser
|
|
136
|
+
runtimes.
|
|
137
|
+
|
|
138
|
+
Custom field factories can use `createPluginField`. Their serializable
|
|
139
|
+
`meta.editor` must match a field declaration in the server plugin and a React
|
|
140
|
+
editor registered by its manager facet.
|
|
141
|
+
|
|
142
|
+
## Content Types
|
|
143
|
+
|
|
144
|
+
A `ContentType` defines a logical collection:
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
const Post = new ContentType({
|
|
148
|
+
name: "Post",
|
|
149
|
+
comments: true,
|
|
150
|
+
menu: {
|
|
151
|
+
title: "Posts",
|
|
152
|
+
icon: "newspaper",
|
|
153
|
+
category: "Content",
|
|
154
|
+
},
|
|
155
|
+
fields: {
|
|
156
|
+
title: Fields.string().required(),
|
|
157
|
+
slug: Fields.string().type("Slug").required(),
|
|
158
|
+
body: Fields.string().type("RichText"),
|
|
159
|
+
published: Fields.boolean(),
|
|
160
|
+
},
|
|
161
|
+
uniques: [["slug"]],
|
|
162
|
+
listFields: ["title", "slug", "published"],
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Page-like content types can define ordered page modules with `iterator` outside
|
|
167
|
+
`fields`. Rakun persists this generated field as `_iterator`:
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
const Page = new ContentType({
|
|
171
|
+
name: "Page",
|
|
172
|
+
fields: {
|
|
173
|
+
title: Fields.string().required(),
|
|
174
|
+
slug: Fields.string().type("Slug").required(),
|
|
175
|
+
},
|
|
176
|
+
iterator: [{ contentType: PageSection, type: "existing" }],
|
|
177
|
+
linkedIterator: true,
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Set `linkedIterator: true` when every document should use one shared module
|
|
182
|
+
structure. The manager stores a canonical iterator for the content type, while
|
|
183
|
+
dynamic bindings such as `Current document` continue to resolve against the
|
|
184
|
+
individual page being rendered. Documents are linked by default and can be
|
|
185
|
+
unlinked in the manager to keep a local copy of the iterator.
|
|
186
|
+
|
|
187
|
+
Main properties:
|
|
188
|
+
|
|
189
|
+
- `name`: stable type name. Also used as `_type`.
|
|
190
|
+
- `fields`: field map.
|
|
191
|
+
- `iterator`: page module entries. Generates the reserved `_iterator` field.
|
|
192
|
+
- `linkedIterator`: shares that iterator between documents while allowing
|
|
193
|
+
explicit per-document overrides.
|
|
194
|
+
- `menu`: manager metadata.
|
|
195
|
+
- `uniques`: unique field groups.
|
|
196
|
+
- `listFields`: preferred fields in lists and relations.
|
|
197
|
+
- `hideFromManager()`: hides the content type from manager content type lists.
|
|
198
|
+
- `apiOnly()`: applies `.apiOnly()` to every field in the content type.
|
|
199
|
+
- `managerOnly()`: applies `.managerOnly()` to every field in the content type.
|
|
200
|
+
- `comments: true` or `enableComments()`: enables manager document comments and user mentions for saved entries.
|
|
201
|
+
- `withHooks()`: attaches lifecycle hooks such as `beforeInsert`, `beforeUpdate`, and `onGet`.
|
|
202
|
+
- Dynamic data bindings are available on manager-visible fields by default; use
|
|
203
|
+
field-level `.noDynamic()` to opt out.
|
|
204
|
+
|
|
205
|
+
When a content type has a configured route with `hasPage: true`, Rakun also
|
|
206
|
+
adds an optional reserved `_seo` relation automatically.
|
|
207
|
+
|
|
208
|
+
Hooks run around DB mutations and public output resolution:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
const User = new ContentType({
|
|
212
|
+
name: "User",
|
|
213
|
+
fields: {
|
|
214
|
+
email: Fields.string().type("Email").required(),
|
|
215
|
+
password: Fields.string().type("Password").required().managerOnly(),
|
|
216
|
+
},
|
|
217
|
+
}).withHooks({
|
|
218
|
+
beforeInsert: ({ data }) => ({
|
|
219
|
+
...data,
|
|
220
|
+
password: hashPassword(String(data.password)),
|
|
221
|
+
}),
|
|
222
|
+
onGet: ({ data }) => ({
|
|
223
|
+
...data,
|
|
224
|
+
displayName: String(data.email).split("@")[0],
|
|
225
|
+
}),
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Dynamic data turns a content type into a reusable layout. The manager can bind
|
|
230
|
+
manager-visible fields to another content item field, or to a generated `href`
|
|
231
|
+
when a source content type has a page route. Fields are dynamic by default; call
|
|
232
|
+
`.noDynamic()` on fields that should not accept bindings or be exported as
|
|
233
|
+
source paths. Source content types are hidden by default; set
|
|
234
|
+
`dynamicDataSource: true` on content types that should appear in the manager
|
|
235
|
+
source selector. Field bindings can also select `Current document` to read values
|
|
236
|
+
from the document being edited without marking its content type as a source.
|
|
237
|
+
|
|
238
|
+
Source field selectors are type-aware. A string target only offers string-like
|
|
239
|
+
source paths, number targets only offer numbers, and boolean targets only offer
|
|
240
|
+
booleans. Object-like source fields are traversed so nested leaf fields can be
|
|
241
|
+
selected, while reserved SEO metadata is omitted from dynamic data mappings.
|
|
242
|
+
The generated `href` source is only shown for content types that have a
|
|
243
|
+
configured route with `hasPage: true`.
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
const Project = new ContentType({
|
|
247
|
+
name: "Project",
|
|
248
|
+
dynamicDataSource: true,
|
|
249
|
+
fields: {
|
|
250
|
+
title: Fields.string().required(),
|
|
251
|
+
slug: Fields.string().type("Slug").required(),
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
const Carousel = new ContentType({
|
|
256
|
+
name: "Carousel",
|
|
257
|
+
fields: {
|
|
258
|
+
title: Fields.string().required(),
|
|
259
|
+
internalNote: Fields.string().noDynamic(),
|
|
260
|
+
items: Fields.blocks([
|
|
261
|
+
{
|
|
262
|
+
name: "CarouselItem",
|
|
263
|
+
field: Fields.relation(CarouselItem, "new"),
|
|
264
|
+
},
|
|
265
|
+
]),
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
List bindings append dynamic items to manually stored items instead of replacing
|
|
271
|
+
the list. If the same stable item id appears in both sources, the dynamically
|
|
272
|
+
resolved item wins and the duplicate manual copy is skipped.
|
|
273
|
+
|
|
274
|
+
A list inside a nested module can also use a compatible relation or blocks array
|
|
275
|
+
from the current document. The manager exposes these sources as
|
|
276
|
+
`Current document · <field>`, infers the content type of each array item, and
|
|
277
|
+
lets each item be mapped with the same field mapping UI used for collections.
|
|
278
|
+
These bindings store a `currentDocument` source alongside the inferred item
|
|
279
|
+
content type:
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
const headerBindings = {
|
|
283
|
+
lists: {
|
|
284
|
+
categories: {
|
|
285
|
+
contentType: LinkItem.name,
|
|
286
|
+
source: {
|
|
287
|
+
kind: "currentDocument",
|
|
288
|
+
contentType: Project.name,
|
|
289
|
+
path: "categories",
|
|
290
|
+
itemName: "Category",
|
|
291
|
+
},
|
|
292
|
+
itemName: "Category",
|
|
293
|
+
map: {
|
|
294
|
+
title: { contentType: LinkItem.name, path: "title" },
|
|
295
|
+
href: { contentType: LinkItem.name, path: "href" },
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
```
|
|
301
|
+
|
|
274
302
|
List query conditions can compare a source field with a value from the current
|
|
275
|
-
document. The manager exposes this as `Current document`; programmatic bindings
|
|
276
|
-
use `{ $current: "path.to.field" }`. For example, a category can query only the
|
|
277
|
-
projects whose related category has the same slug:
|
|
278
|
-
|
|
279
|
-
```ts
|
|
280
|
-
query: {
|
|
281
|
-
filter: {
|
|
282
|
-
"category.slug": { $current: "slug" },
|
|
283
|
-
},
|
|
284
|
-
options: { limit: 10 },
|
|
285
|
-
}
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
Current-document paths are checked against the content type's dynamic field
|
|
289
|
-
rules before the query runs. `_id` is also available for relation queries.
|
|
290
|
-
|
|
303
|
+
document. The manager exposes this as `Current document`; programmatic bindings
|
|
304
|
+
use `{ $current: "path.to.field" }`. For example, a category can query only the
|
|
305
|
+
projects whose related category has the same slug:
|
|
306
|
+
|
|
307
|
+
```ts
|
|
308
|
+
query: {
|
|
309
|
+
filter: {
|
|
310
|
+
"category.slug": { $current: "slug" },
|
|
311
|
+
},
|
|
312
|
+
options: { limit: 10 },
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Current-document paths are checked against the content type's dynamic field
|
|
317
|
+
rules before the query runs. `_id` is also available for relation queries.
|
|
318
|
+
|
|
291
319
|
A list mapping can also collect an array through a reverse relation without
|
|
292
|
-
persisting that relation on the source document. For example, a category gallery
|
|
293
|
-
can create one item per `Category` and collect the images of its related
|
|
294
|
-
`Project` documents:
|
|
295
|
-
|
|
296
|
-
```ts
|
|
297
|
-
const Category = new ContentType({
|
|
298
|
-
name: "Category",
|
|
299
|
-
dynamicDataSource: true,
|
|
300
|
-
fields: {
|
|
301
|
-
title: Fields.string().required(),
|
|
302
|
-
},
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
const Project = new ContentType({
|
|
306
|
-
name: "Project",
|
|
307
|
-
dynamicDataSource: true,
|
|
308
|
-
fields: {
|
|
309
|
-
category: Fields.relation(Category, "existing").required(),
|
|
310
|
-
images: Fields.file().type("Image").multiple().required(),
|
|
311
|
-
},
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
const galleryBindings = {
|
|
315
|
-
lists: {
|
|
316
|
-
items: {
|
|
317
|
-
contentType: Category.name,
|
|
318
|
-
itemName: "CategoriesGalleryItem",
|
|
319
|
-
map: {
|
|
320
|
-
title: { contentType: Category.name, path: "title" },
|
|
321
|
-
images: {
|
|
322
|
-
kind: "relatedCollection",
|
|
323
|
-
contentType: Project.name,
|
|
324
|
-
relation: "category",
|
|
325
|
-
path: "images",
|
|
326
|
-
limit: 10,
|
|
327
|
-
},
|
|
328
|
-
},
|
|
329
|
-
},
|
|
330
|
-
},
|
|
331
|
-
};
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
The related collection query matches `Project.category._id` against the current
|
|
335
|
-
category, preserves project and image order, and flattens the selected array by
|
|
336
|
-
one level. Its numeric limit applies to related projects and is capped at 100.
|
|
337
|
-
|
|
338
|
-
Schema and validation methods:
|
|
339
|
-
|
|
340
|
-
- `getInputSchema()`: write schema. Includes `_type`, `createdBy`, and `updatedBy`.
|
|
341
|
-
- `getSchema()`: persisted schema.
|
|
342
|
-
- `getPopulatedSchema()`: output with populated relations and `_id`.
|
|
343
|
-
- `getOutputSchema()`: public API output.
|
|
344
|
-
- `getOutputSchemaWithoutIterators()`: output variant without iterator fields.
|
|
345
|
-
- `validate`, `partialValidate`, `validateOutput`: Zod helpers.
|
|
346
|
-
|
|
347
|
-
The registry lives in `lib/Registry`:
|
|
348
|
-
|
|
349
|
-
- `registerContentType`, `registerInternalContentType`.
|
|
350
|
-
- `getContentTypes`, `getExternalContentTypes`, `getInternalContentTypes`.
|
|
351
|
-
- `getContentTypesForManager`: returns serializable content types without Zod schemas and without content types marked with `hideFromManager()`.
|
|
352
|
-
- `getContentTypeByName`.
|
|
353
|
-
|
|
354
|
-
## Fields
|
|
355
|
-
|
|
356
|
-
Main factory:
|
|
357
|
-
|
|
358
|
-
```ts
|
|
359
|
-
Fields.string();
|
|
360
|
-
Fields.number();
|
|
361
|
-
Fields.boolean();
|
|
362
|
-
Fields.date();
|
|
363
|
-
Fields.select(["draft", "published"]);
|
|
364
|
-
Fields.relation(Post);
|
|
365
|
-
Fields.contentReference("Post");
|
|
366
|
-
Fields.selfRelation();
|
|
367
|
-
Fields.blocks([{ name: "title", field: Fields.string() }]);
|
|
368
|
-
Fields.array(Fields.string());
|
|
369
|
-
Fields.link();
|
|
370
|
-
Fields.file();
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
Common modifiers:
|
|
374
|
-
|
|
375
|
-
- `.required()`: marks field as required.
|
|
376
|
-
- `.translatable()`: stores values per language with shape `{ _tag: "Translatable", ... }`.
|
|
377
|
-
- `.apiOnly()`: available for API/persistence, hidden from manager.
|
|
378
|
-
- `.managerOnly()`: visible to manager, excluded from API output.
|
|
379
|
-
|
|
380
|
-
Notable fields:
|
|
381
|
-
|
|
382
|
-
- `StringField`: UI `Text`, `Textarea`, `RichText`, `Email`, `Slug`, `Password`, `Id`, `Url`; supports `.min()` and `.max()`.
|
|
383
|
-
- `NumberField`: supports `.min()` and `.max()`.
|
|
384
|
-
- `RelationField`: relation to another `ContentType`; accepts existing references or inline creation. `Fields.relation(Post, "existing")` restricts to existing records; `"new"` restricts to new records. `.multiple()` returns a homogeneous array of relations.
|
|
385
|
-
- `ContentReferenceField`: reference by content type name.
|
|
386
|
-
- `FileField`: integrates media and optimization options.
|
|
387
|
-
- `Fields.blocks(...)`: heterogeneous ordered list. Each item stores a `name` and a `value`, and the value can match one of the named field shapes. Use it for block-like content where different item types can appear in the same list.
|
|
388
|
-
- `Fields.array(...)`: homogeneous ordered list. Every item uses the same field shape. Multi-value fields such as relation `.multiple()` use this backing model.
|
|
389
|
-
- `IteratorField`: repeatable structure based on content type entries.
|
|
390
|
-
|
|
391
|
-
## Derived Types
|
|
392
|
-
|
|
393
|
-
`@rakun-kit/core/types` and `lib/types` derive types from `ContentType`:
|
|
394
|
-
|
|
395
|
-
- `DataInput<T>`: accepted shape for create/update.
|
|
396
|
-
- `DBOutput<T>`: persisted shape with metadata (`_id`, `_type`, timestamps, authorship).
|
|
397
|
-
- `DataPopulated<T>`: shape with populated relations.
|
|
398
|
-
- `DataFront<T>`: public output without `apiOnly` fields.
|
|
399
|
-
- `Filter<T>`, `Query<T>`, `ListInput<T>`, `GetAllInput<T>`: typed filters and list inputs.
|
|
400
|
-
- `MaybeTranslatableValue<T>`, `TranslatableValue<T>`.
|
|
401
|
-
|
|
402
|
-
## ORM and Mongo
|
|
403
|
-
|
|
404
|
-
`core/src/orm` implements `DBService` on top of MongoDB:
|
|
405
|
-
|
|
406
|
-
```ts
|
|
407
|
-
const db = await getMongoService();
|
|
408
|
-
|
|
409
|
-
const post = await db.create(Post, {
|
|
410
|
-
_type: "Post",
|
|
411
|
-
title: "Hello",
|
|
412
|
-
slug: "hello",
|
|
413
|
-
});
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
Operations:
|
|
417
|
-
|
|
418
|
-
- `get(contentType, id, fields?)`
|
|
419
|
-
- `list(contentType, query)`
|
|
420
|
-
- `create(contentType, data)`
|
|
421
|
-
- `update(contentType, id, data)`
|
|
422
|
-
- `updateMany(contentType, filter, data)`
|
|
423
|
-
- `delete(contentType, filter)`
|
|
424
|
-
- `find(contentType, filter, fields?)`
|
|
425
|
-
- `clear(contentType)`
|
|
426
|
-
- `findDependencies(contentType, id)`
|
|
427
|
-
- `upsert(contentType, filter, data)`
|
|
428
|
-
- `getAll(contentType, query?)`
|
|
429
|
-
|
|
430
|
-
Connection:
|
|
431
|
-
|
|
432
|
-
- `createMongoConnection(config)`: stores config.
|
|
433
|
-
- `createMongoService(config)`: connects and creates handlers.
|
|
434
|
-
- `getMongoService()`: returns the singleton or creates it from config.
|
|
435
|
-
- `closeMongoService()`: closes the connection and clears the singleton.
|
|
436
|
-
|
|
437
|
-
`MongoConfig`:
|
|
438
|
-
|
|
439
|
-
```ts
|
|
440
|
-
type MongoConfig = {
|
|
441
|
-
MONGO_URI: string;
|
|
442
|
-
ENVIRONMENT?: "local" | "development" | "test" | "production";
|
|
443
|
-
};
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
In environments other than `test`, the connection creates indexes defined by `createIndexes`.
|
|
447
|
-
|
|
448
|
-
## API Operations
|
|
449
|
-
|
|
450
|
-
`api/operations` defines typed contracts and handlers for endpoints:
|
|
451
|
-
|
|
452
|
-
- Manager: CRUD, auth, MFA, media, literals, settings.
|
|
453
|
-
- Manager comments: `manager.comments.list`, `manager.comments.create`, and `manager.users.mentions`.
|
|
454
|
-
- Web: page resolution.
|
|
455
|
-
|
|
456
|
-
Main helpers:
|
|
457
|
-
|
|
458
|
-
- `defineOperationContract`: declares a contract with Zod input/output, method, path, and metadata.
|
|
459
|
-
- `defineOperation`: combines a contract with its implementation.
|
|
460
|
-
- `createRakunApiClient`: creates a browser/server HTTP client for custom operations.
|
|
461
|
-
- `GetClient`: derives a typed client from an operation map.
|
|
462
|
-
- `createManagerOperationContracts`, `createWebOperationContracts`.
|
|
463
|
-
- `createManagerOperationDefinitions`, `createWebOperationDefinitions`.
|
|
464
|
-
- `createRakunOperationDefinitions`: combines manager + web.
|
|
465
|
-
- `createOperationManifest`: serializable metadata for clients.
|
|
466
|
-
- `createOperationPath`: HTTP path from operation name.
|
|
467
|
-
- `mergeOperationContracts`: combines maps.
|
|
468
|
-
|
|
469
|
-
`@rakun-kit/core/manager` exposes the manifest and name-based types:
|
|
470
|
-
|
|
471
|
-
```ts
|
|
472
|
-
import {
|
|
473
|
-
managerOperationManifest,
|
|
474
|
-
getManagerOperationMeta,
|
|
475
|
-
type ManagerOperationInput,
|
|
476
|
-
type ManagerOperationOutput,
|
|
477
|
-
} from "@rakun-kit/core/manager";
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
### Custom Operations
|
|
481
|
-
|
|
482
|
-
Applications can define operations in a separate object, pass that object to
|
|
483
|
-
bootstrap, and reuse its type on the frontend:
|
|
484
|
-
|
|
485
|
-
```ts
|
|
486
|
-
// server/api-operations.ts
|
|
487
|
-
import { defineOperation } from "@rakun-kit/core";
|
|
488
|
-
import { z } from "zod";
|
|
489
|
-
|
|
490
|
-
export const apiOperations = {
|
|
491
|
-
"demo.helloWorld": defineOperation<
|
|
492
|
-
{ text: string },
|
|
493
|
-
{ message: string },
|
|
494
|
-
"query",
|
|
495
|
-
"get",
|
|
496
|
-
"public"
|
|
497
|
-
>({
|
|
498
|
-
access: "public",
|
|
499
|
-
kind: "query",
|
|
500
|
-
method: "get",
|
|
501
|
-
description: "Return a hello world message with the provided text",
|
|
502
|
-
input: z.object({
|
|
503
|
-
text: z.string().default("world"),
|
|
504
|
-
}),
|
|
505
|
-
output: z.object({
|
|
506
|
-
message: z.string(),
|
|
507
|
-
}),
|
|
508
|
-
resolve: ({ input }) => ({
|
|
509
|
-
message: `Hello ${input.text}`,
|
|
510
|
-
}),
|
|
511
|
-
}),
|
|
512
|
-
};
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
```ts
|
|
516
|
-
// bootstrap
|
|
517
|
-
import { apiOperations } from "./server/api-operations";
|
|
518
|
-
|
|
519
|
-
rakunBootstrap({
|
|
520
|
-
// ...
|
|
521
|
-
apiOperations,
|
|
522
|
-
});
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
Operation names define their HTTP path: `demo.helloWorld` becomes
|
|
526
|
-
`/demo/helloWorld`.
|
|
527
|
-
|
|
528
|
-
Rules:
|
|
529
|
-
|
|
530
|
-
- Names must not collide with built-in operations.
|
|
531
|
-
- Operations prefixed with `manager.` are included in manager operation routers.
|
|
532
|
-
- Operations prefixed with `web.` are included in web operation routers.
|
|
533
|
-
- Operations with any other prefix are included when using the combined operation registry.
|
|
534
|
-
- Use `access: "public"` for operations called from public web pages.
|
|
535
|
-
- Use `access: "auth"` for operations that require a manager session.
|
|
536
|
-
|
|
537
|
-
The manager route `manager.apiOperations` returns a JSON-serializable operation
|
|
538
|
-
catalog for manager API docs/playgrounds. Input and output Zod schemas are
|
|
539
|
-
converted to JSON Schema for display.
|
|
540
|
-
|
|
541
|
-
### Typed API Client
|
|
542
|
-
|
|
543
|
-
`@rakun-kit/core/web` exposes a small typed HTTP client for operation maps:
|
|
544
|
-
|
|
545
|
-
```ts
|
|
546
|
-
import {
|
|
547
|
-
createRakunApiClient,
|
|
548
|
-
type GetClient,
|
|
549
|
-
} from "@rakun-kit/core/web";
|
|
550
|
-
import type { apiOperations } from "./server/api-operations";
|
|
551
|
-
|
|
552
|
-
type ApiClient = GetClient<typeof apiOperations>;
|
|
553
|
-
|
|
554
|
-
const client: ApiClient = createRakunApiClient<typeof apiOperations>({
|
|
555
|
-
baseUrl: "/api",
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
const result = await client.query("demo.helloWorld", {
|
|
559
|
-
text: "Rakun",
|
|
560
|
-
});
|
|
561
|
-
|
|
562
|
-
result.message;
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
The client exposes:
|
|
566
|
-
|
|
567
|
-
- `query(name, input?, options?)`: only accepts operations with `kind: "query"`.
|
|
568
|
-
- `mutation(name, input?, options?)`: only accepts operations with `kind: "mutation"`.
|
|
569
|
-
|
|
570
|
-
The client derives input and output types from the Zod schemas in
|
|
571
|
-
`apiOperations`.
|
|
572
|
-
|
|
573
|
-
## Request Context and Auth
|
|
574
|
-
|
|
575
|
-
`createRequestContext(input)` normalizes headers, cookies, and response:
|
|
576
|
-
|
|
577
|
-
```ts
|
|
578
|
-
const ctx = await createRequestContext({
|
|
579
|
-
headers: req.headers,
|
|
580
|
-
cookies,
|
|
581
|
-
res: {
|
|
582
|
-
setHeader: res.setHeader.bind(res),
|
|
583
|
-
cookie: res.cookie.bind(res),
|
|
584
|
-
},
|
|
585
|
-
});
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
The resulting context includes:
|
|
589
|
-
|
|
590
|
-
- `req.headers`, `req.cookies`
|
|
591
|
-
- `res.setHeader`, `res.cookie`
|
|
592
|
-
- `user`: manager user or `null`
|
|
593
|
-
- `getUser()`: returns the user or throws `AUTH_REQUIRED`
|
|
594
|
-
|
|
595
|
-
Session cookies are managed with `getSessionCookie` and `setSessionCookie`.
|
|
596
|
-
|
|
597
|
-
## Media
|
|
598
|
-
|
|
599
|
-
Media uses a storage adapter:
|
|
600
|
-
|
|
601
|
-
```ts
|
|
602
|
-
createMediaService({
|
|
603
|
-
adapter,
|
|
604
|
-
defaultAccess: "private",
|
|
605
|
-
defaultGetExpiresInSeconds: 300,
|
|
606
|
-
uploadUrl: "/api/rakun/manager/media/upload",
|
|
607
|
-
});
|
|
608
|
-
```
|
|
609
|
-
|
|
610
|
-
APIs:
|
|
611
|
-
|
|
612
|
-
- `createMediaConnection(config)`: stores config without creating the service.
|
|
613
|
-
- `createMediaService(config)`: creates the singleton with an adapter.
|
|
614
|
-
- `getMediaService()`: returns the singleton or creates it from config.
|
|
615
|
-
- `handleMediaBinaryUpload`: processes manager binary uploads.
|
|
616
|
-
|
|
617
|
-
The service supports prepare/finalize upload, URL generation, folders, and image optimization depending on adapter/configuration.
|
|
618
|
-
|
|
619
|
-
## Literals and Translation
|
|
620
|
-
|
|
621
|
-
Bootstrap receives `literals`. Related utilities:
|
|
622
|
-
|
|
623
|
-
- `getTranslation`: resolves translatable values.
|
|
624
|
-
- `translateObject`: translates objects with translatable fields.
|
|
625
|
-
- `managerLiterals`: base manager texts.
|
|
626
|
-
- Manager schemas for listing/upserting literals.
|
|
627
|
-
|
|
628
|
-
Translatable values use this shape:
|
|
629
|
-
|
|
630
|
-
```ts
|
|
631
|
-
{
|
|
632
|
-
_tag: "Translatable",
|
|
633
|
-
en: "Title",
|
|
634
|
-
es: "Titulo"
|
|
635
|
-
}
|
|
636
|
-
```
|
|
637
|
-
|
|
638
|
-
## Permissions
|
|
639
|
-
|
|
640
|
-
`lib/Permissions` exposes:
|
|
641
|
-
|
|
642
|
-
- `getPermissionList`: generates a permission list.
|
|
643
|
-
- `hasPermissions`: validates user/role permissions.
|
|
644
|
-
- `mapPermissions`: transforms permissions.
|
|
645
|
-
- `Permission`: public type.
|
|
646
|
-
|
|
647
|
-
Manager routes apply permissions, ownership, and auth through utilities in `api/utils`.
|
|
648
|
-
|
|
649
|
-
## Errors
|
|
650
|
-
|
|
651
|
-
Application errors live in `lib/errors`:
|
|
652
|
-
|
|
653
|
-
- `AppError`
|
|
654
|
-
- `throwAppError`
|
|
655
|
-
- `errors`
|
|
656
|
-
- `instanceofAppErrorShape`
|
|
657
|
-
|
|
658
|
-
Database errors live in `orm/dbService`:
|
|
659
|
-
|
|
660
|
-
- `DbError`
|
|
661
|
-
- `DbErrorUnknown`
|
|
662
|
-
- `DbErrorNotFound`
|
|
663
|
-
- `DbErrorInvalidData`
|
|
664
|
-
- `DbErrorConflict`
|
|
665
|
-
- `DbErrorSimulatedFailure`
|
|
666
|
-
|
|
667
|
-
## Runtime Flow
|
|
668
|
-
|
|
669
|
-
1. The app defines content types with `ContentType` and `Fields`.
|
|
670
|
-
2. The app calls `rakunBootstrap(options)`.
|
|
671
|
-
3. The HTTP adapter calls `ensureRakunInitialized()` before serving Rakun routes.
|
|
672
|
-
4. `ensureRakunInitialized()` configures logger, MongoDB, media, and route syncing.
|
|
673
|
-
5. Each request creates a `RakunRequestContext`.
|
|
674
|
-
6. Manager/web operations validate input, run logic, validate output, and return typed contracts.
|
|
675
|
-
|
|
676
|
-
## Tests and Development Notes
|
|
677
|
-
|
|
678
|
-
The package includes targeted tests next to modules (`*.test.ts`), for example ORM, translation, routes, redirects, and populated relations.
|
|
679
|
-
|
|
680
|
-
Package build:
|
|
681
|
-
|
|
682
|
-
```sh
|
|
683
|
-
bun run build --workspace @rakun-kit/core
|
|
684
|
-
```
|
|
685
|
-
|
|
686
|
-
The script generates ESM and CJS in `dist/`, adjusting imports and the CJS `package.json` through repo scripts.
|
|
320
|
+
persisting that relation on the source document. For example, a category gallery
|
|
321
|
+
can create one item per `Category` and collect the images of its related
|
|
322
|
+
`Project` documents:
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
const Category = new ContentType({
|
|
326
|
+
name: "Category",
|
|
327
|
+
dynamicDataSource: true,
|
|
328
|
+
fields: {
|
|
329
|
+
title: Fields.string().required(),
|
|
330
|
+
},
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
const Project = new ContentType({
|
|
334
|
+
name: "Project",
|
|
335
|
+
dynamicDataSource: true,
|
|
336
|
+
fields: {
|
|
337
|
+
category: Fields.relation(Category, "existing").required(),
|
|
338
|
+
images: Fields.file().type("Image").multiple().required(),
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
const galleryBindings = {
|
|
343
|
+
lists: {
|
|
344
|
+
items: {
|
|
345
|
+
contentType: Category.name,
|
|
346
|
+
itemName: "CategoriesGalleryItem",
|
|
347
|
+
map: {
|
|
348
|
+
title: { contentType: Category.name, path: "title" },
|
|
349
|
+
images: {
|
|
350
|
+
kind: "relatedCollection",
|
|
351
|
+
contentType: Project.name,
|
|
352
|
+
relation: "category",
|
|
353
|
+
path: "images",
|
|
354
|
+
limit: 10,
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
};
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
The related collection query matches `Project.category._id` against the current
|
|
363
|
+
category, preserves project and image order, and flattens the selected array by
|
|
364
|
+
one level. Its numeric limit applies to related projects and is capped at 100.
|
|
365
|
+
|
|
366
|
+
Schema and validation methods:
|
|
367
|
+
|
|
368
|
+
- `getInputSchema()`: write schema. Includes `_type`, `createdBy`, and `updatedBy`.
|
|
369
|
+
- `getSchema()`: persisted schema.
|
|
370
|
+
- `getPopulatedSchema()`: output with populated relations and `_id`.
|
|
371
|
+
- `getOutputSchema()`: public API output.
|
|
372
|
+
- `getOutputSchemaWithoutIterators()`: output variant without iterator fields.
|
|
373
|
+
- `validate`, `partialValidate`, `validateOutput`: Zod helpers.
|
|
374
|
+
|
|
375
|
+
The registry lives in `lib/Registry`:
|
|
376
|
+
|
|
377
|
+
- `registerContentType`, `registerInternalContentType`.
|
|
378
|
+
- `getContentTypes`, `getExternalContentTypes`, `getInternalContentTypes`.
|
|
379
|
+
- `getContentTypesForManager`: returns serializable content types without Zod schemas and without content types marked with `hideFromManager()`.
|
|
380
|
+
- `getContentTypeByName`.
|
|
381
|
+
|
|
382
|
+
## Fields
|
|
383
|
+
|
|
384
|
+
Main factory:
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
Fields.string();
|
|
388
|
+
Fields.number();
|
|
389
|
+
Fields.boolean();
|
|
390
|
+
Fields.date();
|
|
391
|
+
Fields.select(["draft", "published"]);
|
|
392
|
+
Fields.relation(Post);
|
|
393
|
+
Fields.contentReference("Post");
|
|
394
|
+
Fields.selfRelation();
|
|
395
|
+
Fields.blocks([{ name: "title", field: Fields.string() }]);
|
|
396
|
+
Fields.array(Fields.string());
|
|
397
|
+
Fields.link();
|
|
398
|
+
Fields.file();
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Common modifiers:
|
|
402
|
+
|
|
403
|
+
- `.required()`: marks field as required.
|
|
404
|
+
- `.translatable()`: stores values per language with shape `{ _tag: "Translatable", ... }`.
|
|
405
|
+
- `.apiOnly()`: available for API/persistence, hidden from manager.
|
|
406
|
+
- `.managerOnly()`: visible to manager, excluded from API output.
|
|
407
|
+
|
|
408
|
+
Notable fields:
|
|
409
|
+
|
|
410
|
+
- `StringField`: UI `Text`, `Textarea`, `RichText`, `Email`, `Slug`, `Password`, `Id`, `Url`; supports `.min()` and `.max()`.
|
|
411
|
+
- `NumberField`: supports `.min()` and `.max()`.
|
|
412
|
+
- `RelationField`: relation to another `ContentType`; accepts existing references or inline creation. `Fields.relation(Post, "existing")` restricts to existing records; `"new"` restricts to new records. `.multiple()` returns a homogeneous array of relations.
|
|
413
|
+
- `ContentReferenceField`: reference by content type name.
|
|
414
|
+
- `FileField`: integrates media and optimization options.
|
|
415
|
+
- `Fields.blocks(...)`: heterogeneous ordered list. Each item stores a `name` and a `value`, and the value can match one of the named field shapes. Use it for block-like content where different item types can appear in the same list.
|
|
416
|
+
- `Fields.array(...)`: homogeneous ordered list. Every item uses the same field shape. Multi-value fields such as relation `.multiple()` use this backing model.
|
|
417
|
+
- `IteratorField`: repeatable structure based on content type entries.
|
|
418
|
+
|
|
419
|
+
## Derived Types
|
|
420
|
+
|
|
421
|
+
`@rakun-kit/core/types` and `lib/types` derive types from `ContentType`:
|
|
422
|
+
|
|
423
|
+
- `DataInput<T>`: accepted shape for create/update.
|
|
424
|
+
- `DBOutput<T>`: persisted shape with metadata (`_id`, `_type`, timestamps, authorship).
|
|
425
|
+
- `DataPopulated<T>`: shape with populated relations.
|
|
426
|
+
- `DataFront<T>`: public output without `apiOnly` fields.
|
|
427
|
+
- `Filter<T>`, `Query<T>`, `ListInput<T>`, `GetAllInput<T>`: typed filters and list inputs.
|
|
428
|
+
- `MaybeTranslatableValue<T>`, `TranslatableValue<T>`.
|
|
429
|
+
|
|
430
|
+
## ORM and Mongo
|
|
431
|
+
|
|
432
|
+
`core/src/orm` implements `DBService` on top of MongoDB:
|
|
433
|
+
|
|
434
|
+
```ts
|
|
435
|
+
const db = await getMongoService();
|
|
436
|
+
|
|
437
|
+
const post = await db.create(Post, {
|
|
438
|
+
_type: "Post",
|
|
439
|
+
title: "Hello",
|
|
440
|
+
slug: "hello",
|
|
441
|
+
});
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
Operations:
|
|
445
|
+
|
|
446
|
+
- `get(contentType, id, fields?)`
|
|
447
|
+
- `list(contentType, query)`
|
|
448
|
+
- `create(contentType, data)`
|
|
449
|
+
- `update(contentType, id, data)`
|
|
450
|
+
- `updateMany(contentType, filter, data)`
|
|
451
|
+
- `delete(contentType, filter)`
|
|
452
|
+
- `find(contentType, filter, fields?)`
|
|
453
|
+
- `clear(contentType)`
|
|
454
|
+
- `findDependencies(contentType, id)`
|
|
455
|
+
- `upsert(contentType, filter, data)`
|
|
456
|
+
- `getAll(contentType, query?)`
|
|
457
|
+
|
|
458
|
+
Connection:
|
|
459
|
+
|
|
460
|
+
- `createMongoConnection(config)`: stores config.
|
|
461
|
+
- `createMongoService(config)`: connects and creates handlers.
|
|
462
|
+
- `getMongoService()`: returns the singleton or creates it from config.
|
|
463
|
+
- `closeMongoService()`: closes the connection and clears the singleton.
|
|
464
|
+
|
|
465
|
+
`MongoConfig`:
|
|
466
|
+
|
|
467
|
+
```ts
|
|
468
|
+
type MongoConfig = {
|
|
469
|
+
MONGO_URI: string;
|
|
470
|
+
ENVIRONMENT?: "local" | "development" | "test" | "production";
|
|
471
|
+
};
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
In environments other than `test`, the connection creates indexes defined by `createIndexes`.
|
|
475
|
+
|
|
476
|
+
## API Operations
|
|
477
|
+
|
|
478
|
+
`api/operations` defines typed contracts and handlers for endpoints:
|
|
479
|
+
|
|
480
|
+
- Manager: CRUD, auth, MFA, media, literals, settings.
|
|
481
|
+
- Manager comments: `manager.comments.list`, `manager.comments.create`, and `manager.users.mentions`.
|
|
482
|
+
- Web: page resolution.
|
|
483
|
+
|
|
484
|
+
Main helpers:
|
|
485
|
+
|
|
486
|
+
- `defineOperationContract`: declares a contract with Zod input/output, method, path, and metadata.
|
|
487
|
+
- `defineOperation`: combines a contract with its implementation.
|
|
488
|
+
- `createRakunApiClient`: creates a browser/server HTTP client for custom operations.
|
|
489
|
+
- `GetClient`: derives a typed client from an operation map.
|
|
490
|
+
- `createManagerOperationContracts`, `createWebOperationContracts`.
|
|
491
|
+
- `createManagerOperationDefinitions`, `createWebOperationDefinitions`.
|
|
492
|
+
- `createRakunOperationDefinitions`: combines manager + web.
|
|
493
|
+
- `createOperationManifest`: serializable metadata for clients.
|
|
494
|
+
- `createOperationPath`: HTTP path from operation name.
|
|
495
|
+
- `mergeOperationContracts`: combines maps.
|
|
496
|
+
|
|
497
|
+
`@rakun-kit/core/manager` exposes the manifest and name-based types:
|
|
498
|
+
|
|
499
|
+
```ts
|
|
500
|
+
import {
|
|
501
|
+
managerOperationManifest,
|
|
502
|
+
getManagerOperationMeta,
|
|
503
|
+
type ManagerOperationInput,
|
|
504
|
+
type ManagerOperationOutput,
|
|
505
|
+
} from "@rakun-kit/core/manager";
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### Custom Operations
|
|
509
|
+
|
|
510
|
+
Applications can define operations in a separate object, pass that object to
|
|
511
|
+
bootstrap, and reuse its type on the frontend:
|
|
512
|
+
|
|
513
|
+
```ts
|
|
514
|
+
// server/api-operations.ts
|
|
515
|
+
import { defineOperation } from "@rakun-kit/core";
|
|
516
|
+
import { z } from "zod";
|
|
517
|
+
|
|
518
|
+
export const apiOperations = {
|
|
519
|
+
"demo.helloWorld": defineOperation<
|
|
520
|
+
{ text: string },
|
|
521
|
+
{ message: string },
|
|
522
|
+
"query",
|
|
523
|
+
"get",
|
|
524
|
+
"public"
|
|
525
|
+
>({
|
|
526
|
+
access: "public",
|
|
527
|
+
kind: "query",
|
|
528
|
+
method: "get",
|
|
529
|
+
description: "Return a hello world message with the provided text",
|
|
530
|
+
input: z.object({
|
|
531
|
+
text: z.string().default("world"),
|
|
532
|
+
}),
|
|
533
|
+
output: z.object({
|
|
534
|
+
message: z.string(),
|
|
535
|
+
}),
|
|
536
|
+
resolve: ({ input }) => ({
|
|
537
|
+
message: `Hello ${input.text}`,
|
|
538
|
+
}),
|
|
539
|
+
}),
|
|
540
|
+
};
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
```ts
|
|
544
|
+
// bootstrap
|
|
545
|
+
import { apiOperations } from "./server/api-operations";
|
|
546
|
+
|
|
547
|
+
rakunBootstrap({
|
|
548
|
+
// ...
|
|
549
|
+
apiOperations,
|
|
550
|
+
});
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
Operation names define their HTTP path: `demo.helloWorld` becomes
|
|
554
|
+
`/demo/helloWorld`.
|
|
555
|
+
|
|
556
|
+
Rules:
|
|
557
|
+
|
|
558
|
+
- Names must not collide with built-in operations.
|
|
559
|
+
- Operations prefixed with `manager.` are included in manager operation routers.
|
|
560
|
+
- Operations prefixed with `web.` are included in web operation routers.
|
|
561
|
+
- Operations with any other prefix are included when using the combined operation registry.
|
|
562
|
+
- Use `access: "public"` for operations called from public web pages.
|
|
563
|
+
- Use `access: "auth"` for operations that require a manager session.
|
|
564
|
+
|
|
565
|
+
The manager route `manager.apiOperations` returns a JSON-serializable operation
|
|
566
|
+
catalog for manager API docs/playgrounds. Input and output Zod schemas are
|
|
567
|
+
converted to JSON Schema for display.
|
|
568
|
+
|
|
569
|
+
### Typed API Client
|
|
570
|
+
|
|
571
|
+
`@rakun-kit/core/web` exposes a small typed HTTP client for operation maps:
|
|
572
|
+
|
|
573
|
+
```ts
|
|
574
|
+
import {
|
|
575
|
+
createRakunApiClient,
|
|
576
|
+
type GetClient,
|
|
577
|
+
} from "@rakun-kit/core/web";
|
|
578
|
+
import type { apiOperations } from "./server/api-operations";
|
|
579
|
+
|
|
580
|
+
type ApiClient = GetClient<typeof apiOperations>;
|
|
581
|
+
|
|
582
|
+
const client: ApiClient = createRakunApiClient<typeof apiOperations>({
|
|
583
|
+
baseUrl: "/api",
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
const result = await client.query("demo.helloWorld", {
|
|
587
|
+
text: "Rakun",
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
result.message;
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
The client exposes:
|
|
594
|
+
|
|
595
|
+
- `query(name, input?, options?)`: only accepts operations with `kind: "query"`.
|
|
596
|
+
- `mutation(name, input?, options?)`: only accepts operations with `kind: "mutation"`.
|
|
597
|
+
|
|
598
|
+
The client derives input and output types from the Zod schemas in
|
|
599
|
+
`apiOperations`.
|
|
600
|
+
|
|
601
|
+
## Request Context and Auth
|
|
602
|
+
|
|
603
|
+
`createRequestContext(input)` normalizes headers, cookies, and response:
|
|
604
|
+
|
|
605
|
+
```ts
|
|
606
|
+
const ctx = await createRequestContext({
|
|
607
|
+
headers: req.headers,
|
|
608
|
+
cookies,
|
|
609
|
+
res: {
|
|
610
|
+
setHeader: res.setHeader.bind(res),
|
|
611
|
+
cookie: res.cookie.bind(res),
|
|
612
|
+
},
|
|
613
|
+
});
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
The resulting context includes:
|
|
617
|
+
|
|
618
|
+
- `req.headers`, `req.cookies`
|
|
619
|
+
- `res.setHeader`, `res.cookie`
|
|
620
|
+
- `user`: manager user or `null`
|
|
621
|
+
- `getUser()`: returns the user or throws `AUTH_REQUIRED`
|
|
622
|
+
|
|
623
|
+
Session cookies are managed with `getSessionCookie` and `setSessionCookie`.
|
|
624
|
+
|
|
625
|
+
## Media
|
|
626
|
+
|
|
627
|
+
Media uses a storage adapter:
|
|
628
|
+
|
|
629
|
+
```ts
|
|
630
|
+
createMediaService({
|
|
631
|
+
adapter,
|
|
632
|
+
defaultAccess: "private",
|
|
633
|
+
defaultGetExpiresInSeconds: 300,
|
|
634
|
+
uploadUrl: "/api/rakun/manager/media/upload",
|
|
635
|
+
});
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
APIs:
|
|
639
|
+
|
|
640
|
+
- `createMediaConnection(config)`: stores config without creating the service.
|
|
641
|
+
- `createMediaService(config)`: creates the singleton with an adapter.
|
|
642
|
+
- `getMediaService()`: returns the singleton or creates it from config.
|
|
643
|
+
- `handleMediaBinaryUpload`: processes manager binary uploads.
|
|
644
|
+
|
|
645
|
+
The service supports prepare/finalize upload, URL generation, folders, and image optimization depending on adapter/configuration.
|
|
646
|
+
|
|
647
|
+
## Literals and Translation
|
|
648
|
+
|
|
649
|
+
Bootstrap receives `literals`. Related utilities:
|
|
650
|
+
|
|
651
|
+
- `getTranslation`: resolves translatable values.
|
|
652
|
+
- `translateObject`: translates objects with translatable fields.
|
|
653
|
+
- `managerLiterals`: base manager texts.
|
|
654
|
+
- Manager schemas for listing/upserting literals.
|
|
655
|
+
|
|
656
|
+
Translatable values use this shape:
|
|
657
|
+
|
|
658
|
+
```ts
|
|
659
|
+
{
|
|
660
|
+
_tag: "Translatable",
|
|
661
|
+
en: "Title",
|
|
662
|
+
es: "Titulo"
|
|
663
|
+
}
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
## Permissions
|
|
667
|
+
|
|
668
|
+
`lib/Permissions` exposes:
|
|
669
|
+
|
|
670
|
+
- `getPermissionList`: generates a permission list.
|
|
671
|
+
- `hasPermissions`: validates user/role permissions.
|
|
672
|
+
- `mapPermissions`: transforms permissions.
|
|
673
|
+
- `Permission`: public type.
|
|
674
|
+
|
|
675
|
+
Manager routes apply permissions, ownership, and auth through utilities in `api/utils`.
|
|
676
|
+
|
|
677
|
+
## Errors
|
|
678
|
+
|
|
679
|
+
Application errors live in `lib/errors`:
|
|
680
|
+
|
|
681
|
+
- `AppError`
|
|
682
|
+
- `throwAppError`
|
|
683
|
+
- `errors`
|
|
684
|
+
- `instanceofAppErrorShape`
|
|
685
|
+
|
|
686
|
+
Database errors live in `orm/dbService`:
|
|
687
|
+
|
|
688
|
+
- `DbError`
|
|
689
|
+
- `DbErrorUnknown`
|
|
690
|
+
- `DbErrorNotFound`
|
|
691
|
+
- `DbErrorInvalidData`
|
|
692
|
+
- `DbErrorConflict`
|
|
693
|
+
- `DbErrorSimulatedFailure`
|
|
694
|
+
|
|
695
|
+
## Runtime Flow
|
|
696
|
+
|
|
697
|
+
1. The app defines content types with `ContentType` and `Fields`.
|
|
698
|
+
2. The app calls `rakunBootstrap(options)`.
|
|
699
|
+
3. The HTTP adapter calls `ensureRakunInitialized()` before serving Rakun routes.
|
|
700
|
+
4. `ensureRakunInitialized()` configures logger, MongoDB, media, and route syncing.
|
|
701
|
+
5. Each request creates a `RakunRequestContext`.
|
|
702
|
+
6. Manager/web operations validate input, run logic, validate output, and return typed contracts.
|
|
703
|
+
|
|
704
|
+
## Tests and Development Notes
|
|
705
|
+
|
|
706
|
+
The package includes targeted tests next to modules (`*.test.ts`), for example ORM, translation, routes, redirects, and populated relations.
|
|
707
|
+
|
|
708
|
+
Package build:
|
|
709
|
+
|
|
710
|
+
```sh
|
|
711
|
+
bun run build --workspace @rakun-kit/core
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
The script generates ESM and CJS in `dist/`, adjusting imports and the CJS `package.json` through repo scripts.
|