@cdmbase/wiki-browser 12.0.18-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/lib/components/Logo.d.ts +4 -0
- package/lib/components/Logo.d.ts.map +1 -0
- package/lib/components/Logo.js +16 -0
- package/lib/components/Logo.js.map +1 -0
- package/lib/components/help/SidebarSearch.d.ts +8 -0
- package/lib/components/help/SidebarSearch.d.ts.map +1 -0
- package/lib/components/help/SidebarSearch.js +111 -0
- package/lib/components/help/SidebarSearch.js.map +1 -0
- package/lib/components/help/index.d.ts +2 -0
- package/lib/components/help/index.d.ts.map +1 -0
- package/lib/components/landing/FeatureCard.d.ts +13 -0
- package/lib/components/landing/FeatureCard.d.ts.map +1 -0
- package/lib/components/landing/FeatureCard.js +85 -0
- package/lib/components/landing/FeatureCard.js.map +1 -0
- package/lib/components/landing/QuickLinkCard.d.ts +8 -0
- package/lib/components/landing/QuickLinkCard.d.ts.map +1 -0
- package/lib/components/landing/QuickLinkCard.js +26 -0
- package/lib/components/landing/QuickLinkCard.js.map +1 -0
- package/lib/components/landing/SearchInput.d.ts +10 -0
- package/lib/components/landing/SearchInput.d.ts.map +1 -0
- package/lib/components/landing/SearchInput.js +223 -0
- package/lib/components/landing/SearchInput.js.map +1 -0
- package/lib/components/landing/index.d.ts +4 -0
- package/lib/components/landing/index.d.ts.map +1 -0
- package/lib/components/welcome.d.ts +3 -0
- package/lib/components/welcome.d.ts.map +1 -0
- package/lib/compute.d.ts +4 -0
- package/lib/compute.d.ts.map +1 -0
- package/lib/compute.js +96 -0
- package/lib/compute.js.map +1 -0
- package/lib/config/env-config.d.ts +4 -0
- package/lib/config/env-config.d.ts.map +1 -0
- package/lib/config/env-config.js +7 -0
- package/lib/config/env-config.js.map +1 -0
- package/lib/docs.config.d.ts +48 -0
- package/lib/docs.config.d.ts.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -0
- package/lib/loaders/search.d.ts +1 -0
- package/lib/loaders/search.d.ts.map +1 -0
- package/lib/module.d.ts +4 -0
- package/lib/module.d.ts.map +1 -0
- package/lib/module.js +11 -0
- package/lib/module.js.map +1 -0
- package/lib/pages/ArticlePage/ArticlePage.d.ts +4 -0
- package/lib/pages/ArticlePage/ArticlePage.d.ts.map +1 -0
- package/lib/pages/ArticlePage/ArticlePage.js +222 -0
- package/lib/pages/ArticlePage/ArticlePage.js.map +1 -0
- package/lib/pages/ArticlePage/index.d.ts +3 -0
- package/lib/pages/ArticlePage/index.d.ts.map +1 -0
- package/lib/pages/ArticlePage/index.js +3 -0
- package/lib/pages/ArticlePage/index.js.map +1 -0
- package/lib/pages/CategoryCollection/CategoryCollection.d.ts +4 -0
- package/lib/pages/CategoryCollection/CategoryCollection.d.ts.map +1 -0
- package/lib/pages/CategoryCollection/CategoryCollection.js +103 -0
- package/lib/pages/CategoryCollection/CategoryCollection.js.map +1 -0
- package/lib/pages/CategoryCollection/index.d.ts +3 -0
- package/lib/pages/CategoryCollection/index.d.ts.map +1 -0
- package/lib/pages/CategoryCollection/index.js +3 -0
- package/lib/pages/CategoryCollection/index.js.map +1 -0
- package/lib/pages/Help/HelpIndex.d.ts +4 -0
- package/lib/pages/Help/HelpIndex.d.ts.map +1 -0
- package/lib/pages/Help/HelpIndex.js +44 -0
- package/lib/pages/Help/HelpIndex.js.map +1 -0
- package/lib/pages/Help/index.d.ts +4 -0
- package/lib/pages/Help/index.d.ts.map +1 -0
- package/lib/pages/Help/index.js +226 -0
- package/lib/pages/Help/index.js.map +1 -0
- package/lib/pages/Landing/index.d.ts +3 -0
- package/lib/pages/Landing/index.d.ts.map +1 -0
- package/lib/pages/Landing/index.js +281 -0
- package/lib/pages/Landing/index.js.map +1 -0
- package/lib/routes.json +2533 -0
- package/lib/seo.d.ts +22 -0
- package/lib/seo.d.ts.map +1 -0
- package/lib/slot-fill/FooterFill.d.ts +3 -0
- package/lib/slot-fill/FooterFill.d.ts.map +1 -0
- package/lib/slot-fill/FooterFill.js +18 -0
- package/lib/slot-fill/FooterFill.js.map +1 -0
- package/lib/slot-fill/LogoFill.d.ts +5 -0
- package/lib/slot-fill/LogoFill.d.ts.map +1 -0
- package/lib/slot-fill/LogoFill.js +74 -0
- package/lib/slot-fill/LogoFill.js.map +1 -0
- package/lib/slot-fill/consts.d.ts +5 -0
- package/lib/slot-fill/consts.d.ts.map +1 -0
- package/lib/slot-fill/consts.js +1 -0
- package/lib/slot-fill/consts.js.map +1 -0
- package/lib/slot-fill/index.d.ts +4 -0
- package/lib/slot-fill/index.d.ts.map +1 -0
- package/lib/templates/assets/images/add-link-frontend.png +0 -0
- package/lib/templates/assets/images/add-package-backend.png +0 -0
- package/lib/templates/assets/images/add-to-backend-module.png +0 -0
- package/lib/templates/assets/images/add-upload-client-frontend.png +0 -0
- package/lib/templates/assets/images/additional-parameters.png +0 -0
- package/lib/templates/assets/images/aeh-implementation.png +0 -0
- package/lib/templates/assets/images/aeh-usage.png +0 -0
- package/lib/templates/assets/images/apollo-client/recommendation_cache_mgmt.png +0 -0
- package/lib/templates/assets/images/app-deploy-new-version/jenkins1.PNG +0 -0
- package/lib/templates/assets/images/app-deploy-new-version/jenkins2.PNG +0 -0
- package/lib/templates/assets/images/auth-wrapper-code.png +0 -0
- package/lib/templates/assets/images/cdebase.png +0 -0
- package/lib/templates/assets/images/cdm-locales-directory.png +0 -0
- package/lib/templates/assets/images/client-settings.png +0 -0
- package/lib/templates/assets/images/codegen_file_update.png +0 -0
- package/lib/templates/assets/images/configuration.png +0 -0
- package/lib/templates/assets/images/copy-plugin.png +0 -0
- package/lib/templates/assets/images/docusaurus.png +0 -0
- package/lib/templates/assets/images/error-link.png +0 -0
- package/lib/templates/assets/images/error-sample.png +0 -0
- package/lib/templates/assets/images/extension copy.png +0 -0
- package/lib/templates/assets/images/extension.png +0 -0
- package/lib/templates/assets/images/graphql/graphql-folder-backend.png +0 -0
- package/lib/templates/assets/images/graphql/graphql-folder-with-gql.png +0 -0
- package/lib/templates/assets/images/i18n-config.png +0 -0
- package/lib/templates/assets/images/image.png +0 -0
- package/lib/templates/assets/images/logo.svg +10 -0
- package/lib/templates/assets/images/logo1.svg +1 -0
- package/lib/templates/assets/images/modify-upload-false-server.png +0 -0
- package/lib/templates/assets/images/navigation-auth-enabled.png +0 -0
- package/lib/templates/assets/images/org-dashboard-navigation.png +0 -0
- package/lib/templates/assets/images/org-navigation.png +0 -0
- package/lib/templates/assets/images/preferences_graphql_type.png +0 -0
- package/lib/templates/assets/images/provider.png +0 -0
- package/lib/templates/assets/images/route-config.png +0 -0
- package/lib/templates/assets/images/service-accounts.png +0 -0
- package/lib/templates/assets/images/source-code/source-code-environments.png +0 -0
- package/lib/templates/assets/images/source-code/source-code-organization.png +0 -0
- package/lib/templates/assets/images/spin-clone-develop-deployment/jenkins-changes.png +0 -0
- package/lib/templates/assets/images/spin-clone-develop-deployment/lerna-changes.png +0 -0
- package/lib/templates/assets/images/spin-clone-develop-deployment/root-package-json-changes.png +0 -0
- package/lib/templates/assets/images/spin-clone-develop-deployment/values-dev-changes.png +0 -0
- package/lib/templates/assets/images/sso-mappers.png +0 -0
- package/lib/templates/assets/images/sso-picture-mapper.png +0 -0
- package/lib/templates/assets/images/sso-settings.png +0 -0
- package/lib/templates/assets/images/timesheet_apollo_cache.png +0 -0
- package/lib/templates/assets/images/timesheet_query.png +0 -0
- package/lib/templates/assets/images/tutorial/docsVersionDropdown.png +0 -0
- package/lib/templates/assets/images/tutorial/localeDropdown.png +0 -0
- package/lib/templates/assets/images/unauthenticated.png +0 -0
- package/lib/templates/assets/images/undraw_docusaurus_mountain.svg +170 -0
- package/lib/templates/assets/images/undraw_docusaurus_react.svg +169 -0
- package/lib/templates/assets/images/undraw_docusaurus_tree.svg +1 -0
- package/lib/templates/assets/images/vite-plugin-config.png +0 -0
- package/lib/templates/content/docs/Generators/Project/generate-fullproject.md +12 -0
- package/lib/templates/content/docs/LLM/Logger.llm.md +194 -0
- package/lib/templates/content/docs/LLM/backend-proxies-services-llm.md +2687 -0
- package/lib/templates/content/docs/LLM/backend-service-llm.md +3384 -0
- package/lib/templates/content/docs/LLM/db_migration_llm.md +954 -0
- package/lib/templates/content/docs/LLM/frontend/REMIX-15.3-upgrade-llm.md +1245 -0
- package/lib/templates/content/docs/LLM/inngest/INNGEST_FUNCTION_DEVELOPMENT_GUIDE_LLM.md +1241 -0
- package/lib/templates/content/docs/LLM/inngest/INNGEST_NAMESPACE_LLM.md +384 -0
- package/lib/templates/content/docs/LLM/llm_workflow_namespace.md +384 -0
- package/lib/templates/content/docs/LLM/organization-components-form-llm.md +1395 -0
- package/lib/templates/content/docs/LLM/page-component-llm.md +173 -0
- package/lib/templates/content/docs/LLM/preferences-settings-llm.md +2781 -0
- package/lib/templates/content/docs/LLM/tailwind-css-llm.md +502 -0
- package/lib/templates/content/docs/UI/SchemaBasedUI.md +334 -0
- package/lib/templates/content/docs/UI/SlotFillComponent.md +334 -0
- package/lib/templates/content/docs/adminide-modules/account/auth0-login.md +31 -0
- package/lib/templates/content/docs/adminide-modules/account/index.md +14 -0
- package/lib/templates/content/docs/adminide-modules/account/keycloak-remix-setup.md +86 -0
- package/lib/templates/content/docs/adminide-modules/account/remix-auth-setup.md +79 -0
- package/lib/templates/content/docs/adminide-modules/account/various-auth-qatest.md +157 -0
- package/lib/templates/content/docs/adminide-modules/api-builders/graphql.md +906 -0
- package/lib/templates/content/docs/adminide-modules/billing/payments/index.md +14 -0
- package/lib/templates/content/docs/adminide-modules/billing/payments/stripe/index.md +14 -0
- package/lib/templates/content/docs/adminide-modules/billing/payments/stripe/settingup-stripe-locally.md +25 -0
- package/lib/templates/content/docs/adminide-modules/billing/tier-config.md +293 -0
- package/lib/templates/content/docs/adminide-modules/connectors/Connector.md +207 -0
- package/lib/templates/content/docs/adminide-modules/file-upload/index.md +16 -0
- package/lib/templates/content/docs/adminide-modules/file-upload/setup.md +435 -0
- package/lib/templates/content/docs/adminide-modules/file-upload/upload-file-using-signed-url.md +161 -0
- package/lib/templates/content/docs/adminide-modules/preferences/AddAdditionalPermissions.md +151 -0
- package/lib/templates/content/docs/adminide-modules/preferences/Configuration.md +241 -0
- package/lib/templates/content/docs/adminide-modules/preferences/Policy-Configuration.md +61 -0
- package/lib/templates/content/docs/adminide-modules/preferences/UI-components/ResourceSettingsLoader.md +319 -0
- package/lib/templates/content/docs/adminide-modules/preferences/contribute_scope_target.md +280 -0
- package/lib/templates/content/docs/adminide-modules/preferences/generate-urii.md +94 -0
- package/lib/templates/content/docs/adminide-modules/preferences/index.md +28 -0
- package/lib/templates/content/docs/adminide-modules/preferences/machine-configuration.md +157 -0
- package/lib/templates/content/docs/adminide-modules/preferences/pageSettings/generateCdecodeUri.md +1289 -0
- package/lib/templates/content/docs/adminide-modules/preferences/pageSettings/migratingFromUseSettings.md +215 -0
- package/lib/templates/content/docs/adminide-modules/preferences/permissions/Roles-Permissions.md +72 -0
- package/lib/templates/content/docs/adminide-modules/preferences/permissions/settingUserPermissions.md +139 -0
- package/lib/templates/content/docs/adminide-modules/preferences/preference-dependency.md +138 -0
- package/lib/templates/content/docs/adminide-modules/preferences/route-based-configuration.md +41 -0
- package/lib/templates/content/docs/adminide-modules/preferences/schema-configuration.md +71 -0
- package/lib/templates/content/docs/adminide-modules/preferences/supported.md +24 -0
- package/lib/templates/content/docs/adminide-modules/preferences/useSettingsLoader.md +248 -0
- package/lib/templates/content/docs/adminide-modules/project-tools/auth-providers.md +1317 -0
- package/lib/templates/content/docs/adminide-modules/project-tools/keycloak-guide.md +543 -0
- package/lib/templates/content/docs/adminide-modules/project-tools/tenant-management/tenant-based-authentication.md +846 -0
- package/lib/templates/content/docs/adminide-modules/project-tools/tenant-management/tenant-management.md +708 -0
- package/lib/templates/content/docs/adminide-modules/project-tools/tenant-management/tenants.md +1117 -0
- package/lib/templates/content/docs/chrome-extension/index.md +14 -0
- package/lib/templates/content/docs/chrome-extension/setup.md +30 -0
- package/lib/templates/content/docs/contributing/adding-package.md +23 -0
- package/lib/templates/content/docs/contributing/adding_new_modules.md +99 -0
- package/lib/templates/content/docs/contributing/architecture-updates.md +19 -0
- package/lib/templates/content/docs/contributing/avoid-using-promises-ui.md +116 -0
- package/lib/templates/content/docs/contributing/coding-guidelines.md +111 -0
- package/lib/templates/content/docs/contributing/do-and-dont.md +42 -0
- package/lib/templates/content/docs/contributing/faq.md +22 -0
- package/lib/templates/content/docs/contributing/folder-setup/browser.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/config.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/containers-server.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/core.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/graphql.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/index.md +30 -0
- package/lib/templates/content/docs/contributing/folder-setup/module.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/server.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/services.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/store.md +12 -0
- package/lib/templates/content/docs/contributing/frontend-coding.md +30 -0
- package/lib/templates/content/docs/contributing/git-subtree-sharing.md +73 -0
- package/lib/templates/content/docs/contributing/graphql-subscriptions.md +69 -0
- package/lib/templates/content/docs/contributing/how-to-contribute.md +30 -0
- package/lib/templates/content/docs/contributing/how_to_check_pure_esm.md +29 -0
- package/lib/templates/content/docs/contributing/index.md +60 -0
- package/lib/templates/content/docs/contributing/installation-issues.md +23 -0
- package/lib/templates/content/docs/contributing/keyboard-shortcut.md +131 -0
- package/lib/templates/content/docs/contributing/language/locale-support.md +12 -0
- package/lib/templates/content/docs/contributing/lerna-build-tools.md +516 -0
- package/lib/templates/content/docs/contributing/lerna-yarn-workspaces.md +95 -0
- package/lib/templates/content/docs/contributing/lint-and-formatter.md +20 -0
- package/lib/templates/content/docs/contributing/mobile-setup.md +16 -0
- package/lib/templates/content/docs/contributing/project-setup.md +233 -0
- package/lib/templates/content/docs/contributing/react/index.md +14 -0
- package/lib/templates/content/docs/contributing/react/lazy-component.md +70 -0
- package/lib/templates/content/docs/contributing/run-various-options.md +124 -0
- package/lib/templates/content/docs/contributing/schema-first-graphql-types.md +37 -0
- package/lib/templates/content/docs/contributing/source-code-organization.md +57 -0
- package/lib/templates/content/docs/contributing/staging-docker.md +88 -0
- package/lib/templates/content/docs/contributing/third-party/apollo-client-v3-tutorials.md +28 -0
- package/lib/templates/content/docs/contributing/third-party/index.md +18 -0
- package/lib/templates/content/docs/contributing/typescript-contribution.md +16 -0
- package/lib/templates/content/docs/devops/app-deploy-new-version.md +30 -0
- package/lib/templates/content/docs/devops/index.md +14 -0
- package/lib/templates/content/docs/devops/mobile-jenkins-build.md +40 -0
- package/lib/templates/content/docs/devops/versioning-the-project.md +128 -0
- package/lib/templates/content/docs/error-handler/application-error-handler.md +40 -0
- package/lib/templates/content/docs/error-handler/error-handling.md +26 -0
- package/lib/templates/content/docs/error-handler/index.md +16 -0
- package/lib/templates/content/docs/error-handler/logging-errors.md +14 -0
- package/lib/templates/content/docs/feature-api/copy-operation.md +427 -0
- package/lib/templates/content/docs/feature-api/feature-browser/assets.md +46 -0
- package/lib/templates/content/docs/feature-api/feature-browser/auth-permissions.md +12 -0
- package/lib/templates/content/docs/feature-api/feature-browser/feature.md +131 -0
- package/lib/templates/content/docs/feature-api/feature-browser/index.md +22 -0
- package/lib/templates/content/docs/feature-api/feature-browser/routes-menu.md +110 -0
- package/lib/templates/content/docs/feature-api/feature-browser/routing-convention.md +124 -0
- package/lib/templates/content/docs/feature-api/feature-browser/routing.md +338 -0
- package/lib/templates/content/docs/feature-api/feature-mobile/auth-permissions.md +20 -0
- package/lib/templates/content/docs/feature-api/feature-mobile/feature.md +130 -0
- package/lib/templates/content/docs/feature-api/feature-mobile/index.md +18 -0
- package/lib/templates/content/docs/feature-api/feature-mobile/navigation.md +187 -0
- package/lib/templates/content/docs/feature-api/feature-server/Scheduling.md +44 -0
- package/lib/templates/content/docs/feature-api/feature-server/dataloader.md +320 -0
- package/lib/templates/content/docs/feature-api/feature-server/dependency-injection.md +81 -0
- package/lib/templates/content/docs/feature-api/feature-server/feature.md +65 -0
- package/lib/templates/content/docs/feature-api/feature-server/generic-dataloader.md +135 -0
- package/lib/templates/content/docs/feature-api/feature-server/index.md +40 -0
- package/lib/templates/content/docs/feature-api/feature-server/migration.md +127 -0
- package/lib/templates/content/docs/feature-api/feature-server/mongo-model.md +72 -0
- package/lib/templates/content/docs/feature-api/feature-server/permissions.md +12 -0
- package/lib/templates/content/docs/feature-api/feature-server/policies.md +57 -0
- package/lib/templates/content/docs/feature-api/feature-server/preferences.md +57 -0
- package/lib/templates/content/docs/feature-api/feature-server/repositories.md +114 -0
- package/lib/templates/content/docs/feature-api/feature-server/resolvers.md +126 -0
- package/lib/templates/content/docs/feature-api/feature-server/rules.md +132 -0
- package/lib/templates/content/docs/feature-api/feature-server/schema.md +12 -0
- package/lib/templates/content/docs/feature-api/feature-server/services.md +102 -0
- package/lib/templates/content/docs/feature-api/feature-server/setup-resource-crud.md +359 -0
- package/lib/templates/content/docs/feature-api/index.md +18 -0
- package/lib/templates/content/docs/graphql/apolloClient-mutation.md +94 -0
- package/lib/templates/content/docs/graphql/index.md +14 -0
- package/lib/templates/content/docs/graphql/scalars.md +15 -0
- package/lib/templates/content/docs/help/index.md +14 -0
- package/lib/templates/content/docs/help/intro.md +16 -0
- package/lib/templates/content/docs/intl/ant-design-menu-translation.md +74 -0
- package/lib/templates/content/docs/intl/intl-namespace.md +129 -0
- package/lib/templates/content/docs/intl/vite-plugin-intl.md +87 -0
- package/lib/templates/content/docs/intl/webpack-plugin-intl.md +12 -0
- package/lib/templates/content/docs/intro.md +18 -0
- package/lib/templates/content/docs/knowledge/basic-fullstack.md +238 -0
- package/lib/templates/content/docs/mailing/index.md +14 -0
- package/lib/templates/content/docs/mailing/mailing-template.md +148 -0
- package/lib/templates/content/docs/mobile/App-navigation-generator.md +410 -0
- package/lib/templates/content/docs/mobile/MobileTestCases.md +264 -0
- package/lib/templates/content/docs/mobile/eas-profile-build.md +107 -0
- package/lib/templates/content/docs/mobile/expo-push-notification-setup.md +216 -0
- package/lib/templates/content/docs/mobile/index.md +14 -0
- package/lib/templates/content/docs/mobile/routes.md +83 -0
- package/lib/templates/content/docs/organization/adding-account-context.md +116 -0
- package/lib/templates/content/docs/organization/adding-org-mobile-navigation.md +22 -0
- package/lib/templates/content/docs/organization/adding-org-web-navigation.md +12 -0
- package/lib/templates/content/docs/organization/index.md +20 -0
- package/lib/templates/content/docs/organization/initialization.md +20 -0
- package/lib/templates/content/docs/organization/organization-resource-vs-resource.md +112 -0
- package/lib/templates/content/docs/remix/configuration/component-structure-best-practices.md +152 -0
- package/lib/templates/content/docs/remix/configuration/configurations.md +218 -0
- package/lib/templates/content/docs/remix/configuration/css-import-and-stylesheets.md +142 -0
- package/lib/templates/content/docs/remix/configuration/dont-subcomponent-network.md +166 -0
- package/lib/templates/content/docs/remix/configuration/generated-data-loaders.md +122 -0
- package/lib/templates/content/docs/remix/configuration/generated-resource-loaders.md +257 -0
- package/lib/templates/content/docs/remix/configuration/query-params-generator.md +216 -0
- package/lib/templates/content/docs/remix/configuration/routes-extra-icons.md +103 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-advanced.md +86 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-auth.md +113 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-best-practices.md +55 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-fields.md +79 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-graphql.md +79 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-index.md +112 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-loaders.md +165 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-middleware.md +196 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-overview.md +53 -0
- package/lib/templates/content/docs/remix/data-loaders.md +43 -0
- package/lib/templates/content/docs/remix/devtools/remix-devtools.md +58 -0
- package/lib/templates/content/docs/remix/examples/changes-using-servercode.md +79 -0
- package/lib/templates/content/docs/remix/extra-icons.md +62 -0
- package/lib/templates/content/docs/remix/extra-links.md +65 -0
- package/lib/templates/content/docs/remix/generated-data-loaders.md +114 -0
- package/lib/templates/content/docs/remix/queryParamsGenerator.md +89 -0
- package/lib/templates/content/docs/remix/resources.md +16 -0
- package/lib/templates/content/docs/remix/styles.md +132 -0
- package/lib/templates/content/docs/remix/wiki.md +12 -0
- package/lib/templates/content/docs/security/auth-wrapper/auth-wrapper.md +24 -0
- package/lib/templates/content/docs/security/index.md +18 -0
- package/lib/templates/content/docs/security/secure-button-mobilenative.md +88 -0
- package/lib/templates/content/docs/security/secure-button-web.md +89 -0
- package/lib/templates/content/docs/server-side/account-customization.md +82 -0
- package/lib/templates/content/docs/server-side/apollo/caching.md +164 -0
- package/lib/templates/content/docs/server-side/backend-architecture/FINAL-DECISION.md +209 -0
- package/lib/templates/content/docs/server-side/backend-architecture/TRUE-FINAL-ARCHITECTURE.md +603 -0
- package/lib/templates/content/docs/server-side/backend-architecture/index1.md +0 -0
- package/lib/templates/content/docs/server-side/backend-coding.md +839 -0
- package/lib/templates/content/docs/server-side/e2b/manageing-template.md +197 -0
- package/lib/templates/content/docs/server-side/index.md +14 -0
- package/lib/templates/content/docs/server-side/inngest-functions-module.md +309 -0
- package/lib/templates/content/docs/server-side/listen-stripe-events.md +43 -0
- package/lib/templates/content/docs/server-side/slug-service.md +323 -0
- package/lib/templates/content/docs/tests/index.md +18 -0
- package/lib/templates/content/docs/tests/jest-test-debug-vscode.md +40 -0
- package/lib/templates/content/docs/tests/known-errors.md +116 -0
- package/lib/templates/content/docs/tests/service-test-template.md +118 -0
- package/lib/templates/content/docs/tests/test-setup.md +93 -0
- package/lib/templates/content/docs/xstate.md +23 -0
- package/lib/types.d.ts +37 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/utils/docsNavigation.d.ts +9 -0
- package/lib/utils/docsNavigation.d.ts.map +1 -0
- package/lib/utils/docsNavigation.js +37 -0
- package/lib/utils/docsNavigation.js.map +1 -0
- package/lib/utils/helpCenterUtils.d.ts +26 -0
- package/lib/utils/helpCenterUtils.d.ts.map +1 -0
- package/lib/utils/index.d.ts +3 -0
- package/lib/utils/index.d.ts.map +1 -0
- package/lib/utils/index.js +3 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/markdownLoader.d.ts +36 -0
- package/lib/utils/markdownLoader.d.ts.map +1 -0
- package/lib/utils/markdownLoader.js +2242 -0
- package/lib/utils/markdownLoader.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,1241 @@
|
|
|
1
|
+
# Complete Guide: Creating Inngest Functions in AdminIDE Stack
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This comprehensive guide provides step-by-step instructions for creating, configuring, and deploying Inngest workflow functions in the AdminIDE Stack project. This guide is designed for AI/LLM assistants and developers to create consistent, production-ready Inngest functions.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
1. [Architecture Overview](#1-architecture-overview)
|
|
12
|
+
2. [Project Structure](#2-project-structure)
|
|
13
|
+
3. [Creating WorkflowNamespace Templates](#3-creating-workflownamespace-templates)
|
|
14
|
+
4. [Creating Inngest Functions](#4-creating-inngest-functions)
|
|
15
|
+
5. [Registering with Feature System](#5-registering-with-feature-system)
|
|
16
|
+
6. [Dependency Injection Patterns](#6-dependency-injection-patterns)
|
|
17
|
+
7. [Step Functions and Workflows](#7-step-functions-and-workflows)
|
|
18
|
+
8. [Triggering Events from Services](#8-triggering-events-from-services)
|
|
19
|
+
9. [Best Practices](#9-best-practices)
|
|
20
|
+
10. [Complete Examples](#10-complete-examples)
|
|
21
|
+
11. [Troubleshooting](#11-troubleshooting)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 1. Architecture Overview
|
|
26
|
+
|
|
27
|
+
### What is Inngest?
|
|
28
|
+
|
|
29
|
+
Inngest is a workflow engine that enables:
|
|
30
|
+
|
|
31
|
+
- **Background Jobs**: Long-running tasks that don't block user requests
|
|
32
|
+
- **Step Functions**: Multi-step workflows with automatic retry and state management
|
|
33
|
+
- **Event-Driven Architecture**: Trigger workflows based on events
|
|
34
|
+
- **Orchestration**: Coordinate multiple services and functions
|
|
35
|
+
|
|
36
|
+
### How It Integrates with AdminIDE Stack
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
40
|
+
│ AdminIDE Stack Architecture │
|
|
41
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
42
|
+
│ │
|
|
43
|
+
│ ┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐ │
|
|
44
|
+
│ │ Feature │───▶│ inngestFunctions │───▶│ /api/inngest │ │
|
|
45
|
+
│ │ System │ │ Factory │ │ Endpoint │ │
|
|
46
|
+
│ └─────────────┘ └──────────────────┘ └─────────────────┘ │
|
|
47
|
+
│ │ │ │ │
|
|
48
|
+
│ ▼ ▼ ▼ │
|
|
49
|
+
│ ┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐ │
|
|
50
|
+
│ │ DI │ │ WorkflowNamespace│ │ Inngest │ │
|
|
51
|
+
│ │ Container │ │ Constants │ │ Cloud/Dev │ │
|
|
52
|
+
│ └─────────────┘ └──────────────────┘ └─────────────────┘ │
|
|
53
|
+
│ │
|
|
54
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Key Components
|
|
58
|
+
|
|
59
|
+
| Component | Purpose |
|
|
60
|
+
| ----------------------- | ----------------------------------------------------------- |
|
|
61
|
+
| **WorkflowNamespace** | Centralized constants for function IDs and event names |
|
|
62
|
+
| **Function Factory** | Creates Inngest functions with DI container access |
|
|
63
|
+
| **Feature System** | Registers functions and exposes `/api/inngest` endpoint |
|
|
64
|
+
| **Service Integration** | Triggers events from services using injected Inngest client |
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 2. Project Structure
|
|
69
|
+
|
|
70
|
+
### Standard Module Structure
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
packages-modules/{module-name}/server/
|
|
74
|
+
├── package.json # Contains cdecode template references
|
|
75
|
+
├── src/
|
|
76
|
+
│ └── modules/{feature}/
|
|
77
|
+
│ ├── templates/
|
|
78
|
+
│ │ └── constants/
|
|
79
|
+
│ │ └── WorkflowNamespace.ts.template # 🔑 Namespace definitions
|
|
80
|
+
│ ├── inngest/
|
|
81
|
+
│ │ ├── index.ts # Export factory function
|
|
82
|
+
│ │ ├── functions.ts # Main factory that combines all functions
|
|
83
|
+
│ │ ├── {action}Function.ts # Individual function implementations
|
|
84
|
+
│ │ └── ...
|
|
85
|
+
│ ├── services/
|
|
86
|
+
│ │ └── {ServiceName}.ts # Services that trigger events
|
|
87
|
+
│ └── module.ts # Feature registration
|
|
88
|
+
└── docs/
|
|
89
|
+
└── inngest/ # Documentation
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Example: user-auth0 Module
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
packages-modules/user-auth0/server/
|
|
96
|
+
├── package.json
|
|
97
|
+
└── src/modules/user-auth/
|
|
98
|
+
├── templates/constants/
|
|
99
|
+
│ └── WorkflowNamespace.ts.template
|
|
100
|
+
├── inngest/
|
|
101
|
+
│ ├── index.ts
|
|
102
|
+
│ ├── functions.ts
|
|
103
|
+
│ ├── configureKeycloakAuthSettings.ts
|
|
104
|
+
│ ├── createCompleteStackFunction.ts
|
|
105
|
+
│ ├── fetchAuthProviderByIdFunction.ts
|
|
106
|
+
│ └── configureAuthenticationProviderJob.ts
|
|
107
|
+
└── module.ts
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 3. Creating WorkflowNamespace Templates
|
|
113
|
+
|
|
114
|
+
### 3.1 Naming Convention
|
|
115
|
+
|
|
116
|
+
**Pattern**: `{MODULE}_{FUNCTION_TYPE}_{SPECIFIC_ACTION}`
|
|
117
|
+
|
|
118
|
+
#### Module Prefixes
|
|
119
|
+
|
|
120
|
+
| Prefix | Module |
|
|
121
|
+
| -------------- | ------------------------- |
|
|
122
|
+
| `TENANT_MGMT` | Tenant Management |
|
|
123
|
+
| `AUTH_MGMT` | Authentication Management |
|
|
124
|
+
| `USER_AUTH` | User Authentication |
|
|
125
|
+
| `BILLING` | Billing Operations |
|
|
126
|
+
| `PROJECT_MGMT` | Project Management |
|
|
127
|
+
| `NOTIFICATION` | Notification Services |
|
|
128
|
+
| `KEY_MGMT` | Key/Secret Management |
|
|
129
|
+
|
|
130
|
+
#### Suffix Types
|
|
131
|
+
|
|
132
|
+
| Suffix | Purpose | Example |
|
|
133
|
+
| ---------- | -------------------- | --------------------------------- |
|
|
134
|
+
| (none) | Function ID | `TENANT_MGMT_CREATE_TENANT` |
|
|
135
|
+
| `_EVENT` | Trigger event name | `TENANT_MGMT_CREATE_TENANT_EVENT` |
|
|
136
|
+
| `_SUCCESS` | Success result event | `TENANT_MGMT_TENANT_CREATED` |
|
|
137
|
+
| `_FAILED` | Failure result event | `TENANT_MGMT_TENANT_FAILED` |
|
|
138
|
+
|
|
139
|
+
### 3.2 Template File Format
|
|
140
|
+
|
|
141
|
+
**Location**: `src/modules/{feature}/templates/constants/WorkflowNamespace.ts.template`
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
export const WorkflowNamespace = {
|
|
145
|
+
// ══════════════════════════════════════════════════════════════════
|
|
146
|
+
// {MODULE_NAME} Module - Function IDs
|
|
147
|
+
// ══════════════════════════════════════════════════════════════════
|
|
148
|
+
|
|
149
|
+
// Main orchestrating workflow
|
|
150
|
+
{PREFIX}_MAIN_WORKFLOW: '{prefix}-main-workflow',
|
|
151
|
+
|
|
152
|
+
// Individual function IDs
|
|
153
|
+
{PREFIX}_CREATE_{ENTITY}: '{prefix}-create-{entity}',
|
|
154
|
+
{PREFIX}_UPDATE_{ENTITY}: '{prefix}-update-{entity}',
|
|
155
|
+
{PREFIX}_DELETE_{ENTITY}: '{prefix}-delete-{entity}',
|
|
156
|
+
{PREFIX}_FETCH_{ENTITY}: '{prefix}-fetch-{entity}',
|
|
157
|
+
|
|
158
|
+
// ══════════════════════════════════════════════════════════════════
|
|
159
|
+
// {MODULE_NAME} Module - Trigger Events (what functions listen for)
|
|
160
|
+
// ══════════════════════════════════════════════════════════════════
|
|
161
|
+
|
|
162
|
+
{PREFIX}_MAIN_EVENT: '{prefix}-main-workflow/trigger',
|
|
163
|
+
{PREFIX}_CREATE_{ENTITY}_EVENT: '{prefix}/create-{entity}-trigger',
|
|
164
|
+
{PREFIX}_UPDATE_{ENTITY}_EVENT: '{prefix}/update-{entity}-trigger',
|
|
165
|
+
{PREFIX}_DELETE_{ENTITY}_EVENT: '{prefix}/delete-{entity}-trigger',
|
|
166
|
+
{PREFIX}_FETCH_{ENTITY}_EVENT: '{prefix}/fetch-{entity}-trigger',
|
|
167
|
+
|
|
168
|
+
// ══════════════════════════════════════════════════════════════════
|
|
169
|
+
// {MODULE_NAME} Module - Result Events (optional, for event chaining)
|
|
170
|
+
// ══════════════════════════════════════════════════════════════════
|
|
171
|
+
|
|
172
|
+
{PREFIX}_{ENTITY}_CREATED: '{prefix}/{entity}-created',
|
|
173
|
+
{PREFIX}_{ENTITY}_UPDATED: '{prefix}/{entity}-updated',
|
|
174
|
+
{PREFIX}_{ENTITY}_DELETED: '{prefix}/{entity}-deleted',
|
|
175
|
+
};
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### 3.3 Real Example: Auth Management
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
export const WorkflowNamespace = {
|
|
182
|
+
// ══════════════════════════════════════════════════════════════════
|
|
183
|
+
// Auth Management Module - Function IDs
|
|
184
|
+
// ══════════════════════════════════════════════════════════════════
|
|
185
|
+
|
|
186
|
+
AUTH_MGMT_CONFIGURE_KEYCLOAK_SETTINGS: 'auth-mgmt-configure-keycloak-settings',
|
|
187
|
+
AUTH_MGMT_UPDATE_KEYCLOAK_SETTINGS: 'auth-mgmt-update-keycloak-settings',
|
|
188
|
+
AUTH_MGMT_CREATE_COMPLETE_STACK_FUNCTION: 'auth-mgmt-create-complete-stack-function',
|
|
189
|
+
AUTH_MGMT_CONFIGURE_AUTH_PROVIDER: 'auth-mgmt-configure-auth-provider',
|
|
190
|
+
AUTH_MGMT_FETCH_AUTH_PROVIDER: 'auth-mgmt-fetch-auth-provider',
|
|
191
|
+
|
|
192
|
+
// ══════════════════════════════════════════════════════════════════
|
|
193
|
+
// Auth Management Module - Trigger Events
|
|
194
|
+
// ══════════════════════════════════════════════════════════════════
|
|
195
|
+
|
|
196
|
+
AUTH_MGMT_CREATE_COMPLETE_STACK_EVENT: 'auth-mgmt-create-complete-stack-trigger',
|
|
197
|
+
AUTH_MGMT_CONFIGURE_KEYCLOAK_SETTINGS_EVENT: 'auth-mgmt/configure-keycloak-settings-trigger',
|
|
198
|
+
AUTH_MGMT_UPDATE_KEYCLOAK_SETTINGS_EVENT: 'auth-mgmt/update-keycloak-settings-trigger',
|
|
199
|
+
AUTH_MGMT_CONFIGURE_AUTH_PROVIDER_EVENT: 'auth-mgmt/configure-auth-provider-trigger',
|
|
200
|
+
AUTH_MGMT_FETCH_AUTH_PROVIDER_EVENT: 'auth-mgmt/fetch-auth-provider-trigger',
|
|
201
|
+
};
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### 3.4 Register Template in package.json
|
|
205
|
+
|
|
206
|
+
Add template reference in `package.json`:
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"cdecode": {
|
|
211
|
+
"common": {
|
|
212
|
+
"constants": ["./${libDir}/modules/{feature}/templates/constants/WorkflowNamespace.ts.template"]
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 3.5 Regenerate Common Module
|
|
219
|
+
|
|
220
|
+
After creating/updating templates:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
yarn regenerateGraphql && yarn generateGraphql
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Or if using lerna:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
lerna run build --scope=common
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 4. Creating Inngest Functions
|
|
235
|
+
|
|
236
|
+
### 4.1 Function Types
|
|
237
|
+
|
|
238
|
+
| Type | Use Case | Container Access |
|
|
239
|
+
| ------------------------- | ------------------------------ | ---------------- |
|
|
240
|
+
| **Simple Function** | Standalone operations | No |
|
|
241
|
+
| **Container Function** | Operations needing services | Yes |
|
|
242
|
+
| **Orchestrator Function** | Coordinates multiple functions | Yes |
|
|
243
|
+
|
|
244
|
+
### 4.2 Simple Function (No Container)
|
|
245
|
+
|
|
246
|
+
**File**: `src/modules/{feature}/inngest/simpleFunction.ts`
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
import { Inngest } from 'inngest';
|
|
250
|
+
import { WorkflowNamespace } from 'common/server';
|
|
251
|
+
|
|
252
|
+
export const simpleFunction = (inngest: Inngest) =>
|
|
253
|
+
inngest.createFunction(
|
|
254
|
+
{
|
|
255
|
+
id: WorkflowNamespace.{PREFIX}_SIMPLE_ACTION,
|
|
256
|
+
name: 'Simple Action Description', // Optional: Human-readable name
|
|
257
|
+
retries: 3, // Optional: Default is 3
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
event: WorkflowNamespace.{PREFIX}_SIMPLE_ACTION_EVENT
|
|
261
|
+
},
|
|
262
|
+
async ({ event, step }) => {
|
|
263
|
+
// Access event data
|
|
264
|
+
const { userId, payload } = event.data;
|
|
265
|
+
|
|
266
|
+
// Single step operation
|
|
267
|
+
const result = await step.run('process-data', async () => {
|
|
268
|
+
// Your business logic here
|
|
269
|
+
return { processed: true, userId };
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
return result;
|
|
273
|
+
},
|
|
274
|
+
);
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### 4.3 Container Function (With DI)
|
|
278
|
+
|
|
279
|
+
**File**: `src/modules/{feature}/inngest/containerFunction.ts`
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
import { Container } from 'inversify';
|
|
283
|
+
import { Inngest } from 'inngest';
|
|
284
|
+
import { WorkflowNamespace, SERVER_TYPES, IMyService } from 'common/server';
|
|
285
|
+
|
|
286
|
+
export const containerFunction = (container: Container, inngest: Inngest) =>
|
|
287
|
+
inngest.createFunction(
|
|
288
|
+
{
|
|
289
|
+
id: WorkflowNamespace.{PREFIX}_CONTAINER_ACTION,
|
|
290
|
+
name: 'Container Action with DI'
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
event: WorkflowNamespace.{PREFIX}_CONTAINER_ACTION_EVENT
|
|
294
|
+
},
|
|
295
|
+
async ({ event, step }) => {
|
|
296
|
+
const { entityId, data } = event.data;
|
|
297
|
+
|
|
298
|
+
// Step 1: Get service from container and perform operation
|
|
299
|
+
const entity = await step.run('fetch-entity', async () => {
|
|
300
|
+
const myService = container.get<IMyService>(SERVER_TYPES.MyService);
|
|
301
|
+
return myService.getById(entityId);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// Step 2: Process with another service
|
|
305
|
+
const processed = await step.run('process-entity', async () => {
|
|
306
|
+
const processorService = container.get<IProcessorService>(SERVER_TYPES.ProcessorService);
|
|
307
|
+
return processorService.process(entity, data);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Step 3: Notify completion
|
|
311
|
+
await step.run('notify-completion', async () => {
|
|
312
|
+
const notificationService = container.get<INotificationService>(SERVER_TYPES.NotificationService);
|
|
313
|
+
await notificationService.notify({
|
|
314
|
+
type: 'entity-processed',
|
|
315
|
+
entityId,
|
|
316
|
+
result: processed,
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
status: 'completed',
|
|
322
|
+
entityId,
|
|
323
|
+
processed,
|
|
324
|
+
};
|
|
325
|
+
},
|
|
326
|
+
);
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### 4.4 Orchestrator Function (Coordinates Other Functions)
|
|
330
|
+
|
|
331
|
+
**File**: `src/modules/{feature}/inngest/mainWorkflow.ts`
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import { Container } from 'inversify';
|
|
335
|
+
import { Inngest } from 'inngest';
|
|
336
|
+
import { WorkflowNamespace } from 'common/server';
|
|
337
|
+
import { createEntityFunction } from './createEntityFunction';
|
|
338
|
+
import { configureEntityFunction } from './configureEntityFunction';
|
|
339
|
+
import { notifyEntityFunction } from './notifyEntityFunction';
|
|
340
|
+
|
|
341
|
+
export const mainWorkflowFunction = (container: Container, inngest: Inngest) =>
|
|
342
|
+
inngest.createFunction(
|
|
343
|
+
{
|
|
344
|
+
id: WorkflowNamespace.{PREFIX}_MAIN_WORKFLOW,
|
|
345
|
+
name: 'Main Orchestration Workflow'
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
event: WorkflowNamespace.{PREFIX}_MAIN_EVENT
|
|
349
|
+
},
|
|
350
|
+
async ({ event, step }) => {
|
|
351
|
+
const { userId, config } = event.data;
|
|
352
|
+
|
|
353
|
+
// Step 1: Invoke create function
|
|
354
|
+
const createResult = await step.invoke(WorkflowNamespace.{PREFIX}_CREATE_ENTITY, {
|
|
355
|
+
function: createEntityFunction(container, inngest),
|
|
356
|
+
data: { userId, config },
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// Step 2: Wait for external process (if needed)
|
|
360
|
+
await step.sleep('wait-for-processing', '5s');
|
|
361
|
+
|
|
362
|
+
// Step 3: Invoke configure function
|
|
363
|
+
const configureResult = await step.invoke(WorkflowNamespace.{PREFIX}_CONFIGURE_ENTITY, {
|
|
364
|
+
function: configureEntityFunction(container, inngest),
|
|
365
|
+
data: {
|
|
366
|
+
entityId: createResult.id,
|
|
367
|
+
config
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// Step 4: Parallel invocations (if supported)
|
|
372
|
+
const notifyResult = await step.invoke(WorkflowNamespace.{PREFIX}_NOTIFY_ENTITY, {
|
|
373
|
+
function: notifyEntityFunction(inngest),
|
|
374
|
+
data: {
|
|
375
|
+
entityId: createResult.id,
|
|
376
|
+
status: 'configured'
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
return {
|
|
381
|
+
status: 'workflow-completed',
|
|
382
|
+
createdEntity: createResult,
|
|
383
|
+
configuration: configureResult,
|
|
384
|
+
notification: notifyResult,
|
|
385
|
+
};
|
|
386
|
+
},
|
|
387
|
+
);
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## 5. Registering with Feature System
|
|
393
|
+
|
|
394
|
+
### 5.1 Create Function Factory
|
|
395
|
+
|
|
396
|
+
**File**: `src/modules/{feature}/inngest/functions.ts`
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
import { Container } from 'inversify';
|
|
400
|
+
import { Inngest } from 'inngest';
|
|
401
|
+
import { simpleFunction } from './simpleFunction';
|
|
402
|
+
import { containerFunction } from './containerFunction';
|
|
403
|
+
import { mainWorkflowFunction } from './mainWorkflow';
|
|
404
|
+
import { createEntityFunction } from './createEntityFunction';
|
|
405
|
+
import { configureEntityFunction } from './configureEntityFunction';
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Factory function that creates all Inngest functions for this module.
|
|
409
|
+
* Called by the Feature system during initialization.
|
|
410
|
+
*/
|
|
411
|
+
export const inngestFunctionsFactory = (args: { container: Container; inngest: Inngest }) => [
|
|
412
|
+
// Simple functions (no container needed)
|
|
413
|
+
simpleFunction(args.inngest),
|
|
414
|
+
|
|
415
|
+
// Container functions (need DI)
|
|
416
|
+
containerFunction(args.container, args.inngest),
|
|
417
|
+
createEntityFunction(args.container, args.inngest),
|
|
418
|
+
configureEntityFunction(args.container, args.inngest),
|
|
419
|
+
|
|
420
|
+
// Orchestrator workflows
|
|
421
|
+
mainWorkflowFunction(args.container, args.inngest),
|
|
422
|
+
];
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### 5.2 Export from Index
|
|
426
|
+
|
|
427
|
+
**File**: `src/modules/{feature}/inngest/index.ts`
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
export { inngestFunctionsFactory } from './functions';
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### 5.3 Register in Feature Module
|
|
434
|
+
|
|
435
|
+
**File**: `src/modules/{feature}/module.ts`
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
import { Feature } from '@common-stack/server-core';
|
|
439
|
+
import { inngestFunctionsFactory } from './inngest';
|
|
440
|
+
import { featureContainer } from './container';
|
|
441
|
+
import { schema, resolver } from './graphql';
|
|
442
|
+
|
|
443
|
+
export default new Feature({
|
|
444
|
+
// GraphQL
|
|
445
|
+
schema,
|
|
446
|
+
createResolversFunc: resolver,
|
|
447
|
+
|
|
448
|
+
// DI Container modules
|
|
449
|
+
createContainerFunc: [featureContainer],
|
|
450
|
+
|
|
451
|
+
// 🔑 Inngest Functions Registration
|
|
452
|
+
inngestFunctions: [({ container, inngest }) => inngestFunctionsFactory({ container, inngest })],
|
|
453
|
+
|
|
454
|
+
// Other feature configuration...
|
|
455
|
+
beforeware: [],
|
|
456
|
+
createServiceFunc: [],
|
|
457
|
+
});
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### 5.4 Alternative: Object Return Format
|
|
461
|
+
|
|
462
|
+
The factory can also return an object (automatically handled):
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
export const inngestFunctionsFactory = (args: { container: Container; inngest: Inngest }) => ({
|
|
466
|
+
simpleFunction: simpleFunction(args.inngest),
|
|
467
|
+
containerFunction: containerFunction(args.container, args.inngest),
|
|
468
|
+
mainWorkflow: mainWorkflowFunction(args.container, args.inngest),
|
|
469
|
+
});
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## 6. Dependency Injection Patterns
|
|
475
|
+
|
|
476
|
+
### 6.1 Accessing Services in Functions
|
|
477
|
+
|
|
478
|
+
```typescript
|
|
479
|
+
import { Container } from 'inversify';
|
|
480
|
+
import { Inngest } from 'inngest';
|
|
481
|
+
import { SERVER_TYPES, IUserService, ITenantService, WorkflowNamespace } from 'common/server';
|
|
482
|
+
import { INTERNAL_SERVER_TYPES } from '../constants';
|
|
483
|
+
|
|
484
|
+
export const myFunction = (container: Container, inngest: Inngest) =>
|
|
485
|
+
inngest.createFunction(
|
|
486
|
+
{ id: WorkflowNamespace.MY_FUNCTION },
|
|
487
|
+
{ event: WorkflowNamespace.MY_FUNCTION_EVENT },
|
|
488
|
+
async ({ event, step }) => {
|
|
489
|
+
// ✅ Get services inside step.run() for proper error handling
|
|
490
|
+
await step.run('step-with-services', async () => {
|
|
491
|
+
// Get services from container
|
|
492
|
+
const userService = container.get<IUserService>(SERVER_TYPES.IUserService);
|
|
493
|
+
const tenantService = container.get<ITenantService>(SERVER_TYPES.TenantService);
|
|
494
|
+
|
|
495
|
+
// Internal services use INTERNAL_SERVER_TYPES
|
|
496
|
+
const internalService = container.get(INTERNAL_SERVER_TYPES.IMyInternalService);
|
|
497
|
+
|
|
498
|
+
// Use services
|
|
499
|
+
const user = await userService.getById(event.data.userId);
|
|
500
|
+
const tenant = await tenantService.getById(event.data.tenantId);
|
|
501
|
+
|
|
502
|
+
return { user, tenant };
|
|
503
|
+
});
|
|
504
|
+
},
|
|
505
|
+
);
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### 6.2 Common Service Identifiers
|
|
509
|
+
|
|
510
|
+
```typescript
|
|
511
|
+
// From common/server - SERVER_TYPES
|
|
512
|
+
SERVER_TYPES.IUserService;
|
|
513
|
+
SERVER_TYPES.TenantService;
|
|
514
|
+
SERVER_TYPES.IAuthProviderService;
|
|
515
|
+
SERVER_TYPES.KeyMgmtSecretService;
|
|
516
|
+
|
|
517
|
+
// From @common-stack/core - CommonType
|
|
518
|
+
CommonType.INNGEST_CLIENT;
|
|
519
|
+
CommonType.REDIS_CLIENT;
|
|
520
|
+
CommonType.MOLECULER_BROKER;
|
|
521
|
+
|
|
522
|
+
// Internal module constants
|
|
523
|
+
INTERNAL_SERVER_TYPES.IMyRepository;
|
|
524
|
+
INTERNAL_SERVER_TYPES.IMyService;
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
## 7. Step Functions and Workflows
|
|
530
|
+
|
|
531
|
+
### 7.1 Step Types
|
|
532
|
+
|
|
533
|
+
| Step Method | Purpose | Example |
|
|
534
|
+
| --------------------- | --------------------------------- | ------------------------- |
|
|
535
|
+
| `step.run()` | Execute code with automatic retry | Database operations |
|
|
536
|
+
| `step.invoke()` | Call another Inngest function | Orchestration |
|
|
537
|
+
| `step.sleep()` | Pause execution | Wait for external process |
|
|
538
|
+
| `step.sleepUntil()` | Sleep until specific time | Scheduled operations |
|
|
539
|
+
| `step.waitForEvent()` | Wait for an event | External triggers |
|
|
540
|
+
| `step.sendEvent()` | Send events to other functions | Event chaining |
|
|
541
|
+
|
|
542
|
+
### 7.2 step.run() - Execute Code
|
|
543
|
+
|
|
544
|
+
```typescript
|
|
545
|
+
// Simple step
|
|
546
|
+
const result = await step.run('step-name', async () => {
|
|
547
|
+
return await someAsyncOperation();
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
// Step with service access
|
|
551
|
+
const user = await step.run('get-user', async () => {
|
|
552
|
+
const userService = container.get<IUserService>(SERVER_TYPES.IUserService);
|
|
553
|
+
return userService.getById(userId);
|
|
554
|
+
});
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
### 7.3 step.invoke() - Call Another Function
|
|
558
|
+
|
|
559
|
+
```typescript
|
|
560
|
+
import { createUserFunction } from './createUserFunction';
|
|
561
|
+
|
|
562
|
+
// Invoke another function
|
|
563
|
+
const userResult = await step.invoke(WorkflowNamespace.USER_CREATE, {
|
|
564
|
+
function: createUserFunction(container, inngest),
|
|
565
|
+
data: {
|
|
566
|
+
email: 'user@example.com',
|
|
567
|
+
name: 'John Doe',
|
|
568
|
+
},
|
|
569
|
+
});
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### 7.4 step.sleep() - Pause Execution
|
|
573
|
+
|
|
574
|
+
```typescript
|
|
575
|
+
// Sleep for duration
|
|
576
|
+
await step.sleep('wait-for-processing', '30s');
|
|
577
|
+
await step.sleep('long-wait', '5m');
|
|
578
|
+
await step.sleep('very-long', '1h');
|
|
579
|
+
|
|
580
|
+
// Sleep until specific time
|
|
581
|
+
await step.sleepUntil('schedule-for-tomorrow', new Date('2024-12-25T10:00:00Z'));
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### 7.5 step.waitForEvent() - Wait for External Event
|
|
585
|
+
|
|
586
|
+
```typescript
|
|
587
|
+
const paymentEvent = await step.waitForEvent('wait-for-payment', {
|
|
588
|
+
event: 'payment.completed',
|
|
589
|
+
timeout: '30m',
|
|
590
|
+
match: 'data.orderId', // Match on orderId
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
if (!paymentEvent) {
|
|
594
|
+
// Timeout occurred
|
|
595
|
+
throw new Error('Payment timeout');
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### 7.6 step.sendEvent() - Emit Events
|
|
600
|
+
|
|
601
|
+
```typescript
|
|
602
|
+
await step.sendEvent('notify-completion', {
|
|
603
|
+
name: WorkflowNamespace.ENTITY_CREATED,
|
|
604
|
+
data: {
|
|
605
|
+
entityId: result.id,
|
|
606
|
+
createdAt: new Date().toISOString(),
|
|
607
|
+
},
|
|
608
|
+
});
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
---
|
|
612
|
+
|
|
613
|
+
## 8. Triggering Events from Services
|
|
614
|
+
|
|
615
|
+
### 8.1 Inject Inngest Client in Service
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
import { injectable, inject } from 'inversify';
|
|
619
|
+
import type { Inngest } from 'inngest';
|
|
620
|
+
import { CommonType } from '@common-stack/core';
|
|
621
|
+
import { WorkflowNamespace } from 'common/server';
|
|
622
|
+
|
|
623
|
+
@injectable()
|
|
624
|
+
export class TenantService implements ITenantService {
|
|
625
|
+
constructor(
|
|
626
|
+
@inject(SERVER_TYPES.TenantRepository)
|
|
627
|
+
private readonly tenantRepository: ITenantRepository,
|
|
628
|
+
|
|
629
|
+
@inject(CommonType.INNGEST_CLIENT)
|
|
630
|
+
private readonly inngestClient: Inngest,
|
|
631
|
+
|
|
632
|
+
@inject('Logger')
|
|
633
|
+
private readonly logger: Logger,
|
|
634
|
+
) {}
|
|
635
|
+
|
|
636
|
+
async createTenant(input: ICreateTenantInput): Promise<ITenant> {
|
|
637
|
+
// Business logic
|
|
638
|
+
const tenant = await this.tenantRepository.create(input);
|
|
639
|
+
|
|
640
|
+
// Trigger Inngest workflow
|
|
641
|
+
await this.inngestClient.send({
|
|
642
|
+
name: WorkflowNamespace.TENANT_MGMT_CREATE_CLIENT_EVENT,
|
|
643
|
+
data: {
|
|
644
|
+
tenantId: tenant.id,
|
|
645
|
+
clientConfigurations: input.clientConfigurations,
|
|
646
|
+
organizationId: input.organization,
|
|
647
|
+
},
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
this.logger.info(`Triggered tenant client creation for ${tenant.id}`);
|
|
651
|
+
return tenant;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
### 8.2 Trigger from GraphQL Resolver
|
|
657
|
+
|
|
658
|
+
```typescript
|
|
659
|
+
import { CommonType } from '@common-stack/core';
|
|
660
|
+
import { WorkflowNamespace } from 'common/server';
|
|
661
|
+
|
|
662
|
+
export const createResolversFunc = (container: Container) => ({
|
|
663
|
+
Mutation: {
|
|
664
|
+
createProject: async (_, { input }, context) => {
|
|
665
|
+
const inngestClient = container.get(CommonType.INNGEST_CLIENT);
|
|
666
|
+
const projectService = container.get(SERVER_TYPES.ProjectService);
|
|
667
|
+
|
|
668
|
+
// Create project
|
|
669
|
+
const project = await projectService.create(input);
|
|
670
|
+
|
|
671
|
+
// Trigger background workflow
|
|
672
|
+
await inngestClient.send({
|
|
673
|
+
name: WorkflowNamespace.PROJECT_MGMT_SETUP_EVENT,
|
|
674
|
+
data: {
|
|
675
|
+
projectId: project.id,
|
|
676
|
+
userId: context.userId,
|
|
677
|
+
config: input.config,
|
|
678
|
+
},
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
return project;
|
|
682
|
+
},
|
|
683
|
+
},
|
|
684
|
+
});
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### 8.3 Send Multiple Events
|
|
688
|
+
|
|
689
|
+
```typescript
|
|
690
|
+
// Send multiple events in parallel
|
|
691
|
+
await Promise.all([
|
|
692
|
+
this.inngestClient.send({
|
|
693
|
+
name: WorkflowNamespace.NOTIFY_ADMIN_EVENT,
|
|
694
|
+
data: { entityId, type: 'created' },
|
|
695
|
+
}),
|
|
696
|
+
this.inngestClient.send({
|
|
697
|
+
name: WorkflowNamespace.AUDIT_LOG_EVENT,
|
|
698
|
+
data: { entityId, action: 'create', userId },
|
|
699
|
+
}),
|
|
700
|
+
this.inngestClient.send({
|
|
701
|
+
name: WorkflowNamespace.SYNC_EXTERNAL_EVENT,
|
|
702
|
+
data: { entityId },
|
|
703
|
+
}),
|
|
704
|
+
]);
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
---
|
|
708
|
+
|
|
709
|
+
## 9. Best Practices
|
|
710
|
+
|
|
711
|
+
### 9.1 Namespace Consistency
|
|
712
|
+
|
|
713
|
+
```typescript
|
|
714
|
+
// ✅ CORRECT: Use WorkflowNamespace constants everywhere
|
|
715
|
+
inngest.createFunction(
|
|
716
|
+
{ id: WorkflowNamespace.TENANT_MGMT_CREATE_TENANT },
|
|
717
|
+
{ event: WorkflowNamespace.TENANT_MGMT_CREATE_TENANT_EVENT },
|
|
718
|
+
async ({ event, step }) => {
|
|
719
|
+
/* ... */
|
|
720
|
+
},
|
|
721
|
+
);
|
|
722
|
+
|
|
723
|
+
// ❌ WRONG: Never hardcode event names
|
|
724
|
+
inngest.createFunction(
|
|
725
|
+
{ id: 'tenant-create' }, // ❌ Hardcoded
|
|
726
|
+
{ event: 'tenant.create' }, // ❌ Hardcoded
|
|
727
|
+
async ({ event, step }) => {
|
|
728
|
+
/* ... */
|
|
729
|
+
},
|
|
730
|
+
);
|
|
731
|
+
|
|
732
|
+
// ❌ WRONG: Never mix namespace systems
|
|
733
|
+
inngest.createFunction(
|
|
734
|
+
{ id: WorkflowNamespace.TENANT_MGMT_CREATE_TENANT },
|
|
735
|
+
{ event: LEGACY_EVENTS.CREATE_TENANT }, // ❌ Mixed systems
|
|
736
|
+
async ({ event, step }) => {
|
|
737
|
+
/* ... */
|
|
738
|
+
},
|
|
739
|
+
);
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
### 9.2 Error Handling
|
|
743
|
+
|
|
744
|
+
```typescript
|
|
745
|
+
export const robustFunction = (container: Container, inngest: Inngest) =>
|
|
746
|
+
inngest.createFunction(
|
|
747
|
+
{
|
|
748
|
+
id: WorkflowNamespace.ROBUST_FUNCTION,
|
|
749
|
+
retries: 5, // Configure retries
|
|
750
|
+
onFailure: async ({ error, event }) => {
|
|
751
|
+
// Handle final failure
|
|
752
|
+
const logger = container.get('Logger');
|
|
753
|
+
logger.error('Function failed after all retries', {
|
|
754
|
+
error,
|
|
755
|
+
eventData: event.data,
|
|
756
|
+
});
|
|
757
|
+
},
|
|
758
|
+
},
|
|
759
|
+
{ event: WorkflowNamespace.ROBUST_FUNCTION_EVENT },
|
|
760
|
+
async ({ event, step }) => {
|
|
761
|
+
try {
|
|
762
|
+
const result = await step.run('risky-operation', async () => {
|
|
763
|
+
// Operation that might fail
|
|
764
|
+
return await riskyOperation();
|
|
765
|
+
});
|
|
766
|
+
return { success: true, result };
|
|
767
|
+
} catch (error) {
|
|
768
|
+
// Log but rethrow to trigger retry
|
|
769
|
+
const logger = container.get('Logger');
|
|
770
|
+
logger.warn('Operation failed, will retry', { error });
|
|
771
|
+
throw error;
|
|
772
|
+
}
|
|
773
|
+
},
|
|
774
|
+
);
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
### 9.3 Data Structure Preservation
|
|
778
|
+
|
|
779
|
+
```typescript
|
|
780
|
+
// ✅ CORRECT: Preserve expected data structure
|
|
781
|
+
await this.inngestClient.send({
|
|
782
|
+
name: WorkflowNamespace.TENANT_MGMT_DELETE_TENANT_EVENT,
|
|
783
|
+
data: {
|
|
784
|
+
clientConfiguration: [secretKey], // Function expects array
|
|
785
|
+
},
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
// ❌ WRONG: Breaking expected data structure
|
|
789
|
+
await this.inngestClient.send({
|
|
790
|
+
name: WorkflowNamespace.TENANT_MGMT_DELETE_TENANT_EVENT,
|
|
791
|
+
data: {
|
|
792
|
+
tenantId, // ❌ Function doesn't expect this
|
|
793
|
+
},
|
|
794
|
+
});
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
### 9.4 Step Naming
|
|
798
|
+
|
|
799
|
+
```typescript
|
|
800
|
+
// ✅ CORRECT: Descriptive step names
|
|
801
|
+
await step.run('fetch-user-from-database', async () => {
|
|
802
|
+
/* ... */
|
|
803
|
+
});
|
|
804
|
+
await step.run('validate-payment-details', async () => {
|
|
805
|
+
/* ... */
|
|
806
|
+
});
|
|
807
|
+
await step.run('send-confirmation-email', async () => {
|
|
808
|
+
/* ... */
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
// ❌ WRONG: Vague step names
|
|
812
|
+
await step.run('step1', async () => {
|
|
813
|
+
/* ... */
|
|
814
|
+
});
|
|
815
|
+
await step.run('do-stuff', async () => {
|
|
816
|
+
/* ... */
|
|
817
|
+
});
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
### 9.5 Function Organization
|
|
821
|
+
|
|
822
|
+
```typescript
|
|
823
|
+
// functions.ts - Keep the factory clean and organized
|
|
824
|
+
export const inngestFunctionsFactory = (args: { container: Container; inngest: Inngest }) => [
|
|
825
|
+
// Group 1: CRUD Operations
|
|
826
|
+
createEntityFunction(args.container, args.inngest),
|
|
827
|
+
updateEntityFunction(args.container, args.inngest),
|
|
828
|
+
deleteEntityFunction(args.container, args.inngest),
|
|
829
|
+
|
|
830
|
+
// Group 2: Workflows
|
|
831
|
+
mainWorkflowFunction(args.container, args.inngest),
|
|
832
|
+
setupWorkflowFunction(args.container, args.inngest),
|
|
833
|
+
|
|
834
|
+
// Group 3: Utility Functions
|
|
835
|
+
syncExternalFunction(args.container, args.inngest),
|
|
836
|
+
cleanupFunction(args.inngest),
|
|
837
|
+
];
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
---
|
|
841
|
+
|
|
842
|
+
## 10. Complete Examples
|
|
843
|
+
|
|
844
|
+
### 10.1 Complete Module Setup
|
|
845
|
+
|
|
846
|
+
#### Step 1: WorkflowNamespace Template
|
|
847
|
+
|
|
848
|
+
**File**: `src/modules/order/templates/constants/WorkflowNamespace.ts.template`
|
|
849
|
+
|
|
850
|
+
```typescript
|
|
851
|
+
export const WorkflowNamespace = {
|
|
852
|
+
// Order Management - Function IDs
|
|
853
|
+
ORDER_MGMT_MAIN_WORKFLOW: 'order-mgmt-main-workflow',
|
|
854
|
+
ORDER_MGMT_CREATE_ORDER: 'order-mgmt-create-order',
|
|
855
|
+
ORDER_MGMT_PROCESS_PAYMENT: 'order-mgmt-process-payment',
|
|
856
|
+
ORDER_MGMT_SEND_CONFIRMATION: 'order-mgmt-send-confirmation',
|
|
857
|
+
ORDER_MGMT_UPDATE_INVENTORY: 'order-mgmt-update-inventory',
|
|
858
|
+
|
|
859
|
+
// Order Management - Trigger Events
|
|
860
|
+
ORDER_MGMT_MAIN_EVENT: 'order-mgmt-main-workflow/trigger',
|
|
861
|
+
ORDER_MGMT_CREATE_ORDER_EVENT: 'order-mgmt/create-order-trigger',
|
|
862
|
+
ORDER_MGMT_PROCESS_PAYMENT_EVENT: 'order-mgmt/process-payment-trigger',
|
|
863
|
+
ORDER_MGMT_SEND_CONFIRMATION_EVENT: 'order-mgmt/send-confirmation-trigger',
|
|
864
|
+
ORDER_MGMT_UPDATE_INVENTORY_EVENT: 'order-mgmt/update-inventory-trigger',
|
|
865
|
+
|
|
866
|
+
// Order Management - Result Events
|
|
867
|
+
ORDER_MGMT_ORDER_CREATED: 'order-mgmt/order-created',
|
|
868
|
+
ORDER_MGMT_PAYMENT_PROCESSED: 'order-mgmt/payment-processed',
|
|
869
|
+
ORDER_MGMT_ORDER_COMPLETED: 'order-mgmt/order-completed',
|
|
870
|
+
};
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
#### Step 2: Individual Functions
|
|
874
|
+
|
|
875
|
+
**File**: `src/modules/order/inngest/createOrderFunction.ts`
|
|
876
|
+
|
|
877
|
+
```typescript
|
|
878
|
+
import { Container } from 'inversify';
|
|
879
|
+
import { Inngest } from 'inngest';
|
|
880
|
+
import { WorkflowNamespace, SERVER_TYPES, IOrderService } from 'common/server';
|
|
881
|
+
|
|
882
|
+
export const createOrderFunction = (container: Container, inngest: Inngest) =>
|
|
883
|
+
inngest.createFunction(
|
|
884
|
+
{
|
|
885
|
+
id: WorkflowNamespace.ORDER_MGMT_CREATE_ORDER,
|
|
886
|
+
name: 'Create Order',
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
event: WorkflowNamespace.ORDER_MGMT_CREATE_ORDER_EVENT,
|
|
890
|
+
},
|
|
891
|
+
async ({ event, step }) => {
|
|
892
|
+
const { userId, items, shippingAddress } = event.data;
|
|
893
|
+
|
|
894
|
+
const order = await step.run('create-order-record', async () => {
|
|
895
|
+
const orderService = container.get<IOrderService>(SERVER_TYPES.OrderService);
|
|
896
|
+
return orderService.create({
|
|
897
|
+
userId,
|
|
898
|
+
items,
|
|
899
|
+
shippingAddress,
|
|
900
|
+
status: 'pending',
|
|
901
|
+
});
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
await step.run('reserve-inventory', async () => {
|
|
905
|
+
const inventoryService = container.get(SERVER_TYPES.InventoryService);
|
|
906
|
+
for (const item of items) {
|
|
907
|
+
await inventoryService.reserve(item.productId, item.quantity);
|
|
908
|
+
}
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
return {
|
|
912
|
+
orderId: order.id,
|
|
913
|
+
status: 'created',
|
|
914
|
+
total: order.total,
|
|
915
|
+
};
|
|
916
|
+
},
|
|
917
|
+
);
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
**File**: `src/modules/order/inngest/processPaymentFunction.ts`
|
|
921
|
+
|
|
922
|
+
```typescript
|
|
923
|
+
import { Container } from 'inversify';
|
|
924
|
+
import { Inngest } from 'inngest';
|
|
925
|
+
import { WorkflowNamespace, SERVER_TYPES } from 'common/server';
|
|
926
|
+
|
|
927
|
+
export const processPaymentFunction = (container: Container, inngest: Inngest) =>
|
|
928
|
+
inngest.createFunction(
|
|
929
|
+
{
|
|
930
|
+
id: WorkflowNamespace.ORDER_MGMT_PROCESS_PAYMENT,
|
|
931
|
+
name: 'Process Payment',
|
|
932
|
+
retries: 3,
|
|
933
|
+
},
|
|
934
|
+
{
|
|
935
|
+
event: WorkflowNamespace.ORDER_MGMT_PROCESS_PAYMENT_EVENT,
|
|
936
|
+
},
|
|
937
|
+
async ({ event, step }) => {
|
|
938
|
+
const { orderId, paymentDetails } = event.data;
|
|
939
|
+
|
|
940
|
+
const paymentResult = await step.run('charge-payment', async () => {
|
|
941
|
+
const paymentService = container.get(SERVER_TYPES.PaymentService);
|
|
942
|
+
return paymentService.charge(orderId, paymentDetails);
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
await step.run('update-order-status', async () => {
|
|
946
|
+
const orderService = container.get(SERVER_TYPES.OrderService);
|
|
947
|
+
await orderService.updateStatus(orderId, 'paid');
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
return {
|
|
951
|
+
orderId,
|
|
952
|
+
paymentId: paymentResult.id,
|
|
953
|
+
status: 'payment-processed',
|
|
954
|
+
};
|
|
955
|
+
},
|
|
956
|
+
);
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
#### Step 3: Orchestrator Workflow
|
|
960
|
+
|
|
961
|
+
**File**: `src/modules/order/inngest/mainWorkflow.ts`
|
|
962
|
+
|
|
963
|
+
```typescript
|
|
964
|
+
import { Container } from 'inversify';
|
|
965
|
+
import { Inngest } from 'inngest';
|
|
966
|
+
import { WorkflowNamespace } from 'common/server';
|
|
967
|
+
import { createOrderFunction } from './createOrderFunction';
|
|
968
|
+
import { processPaymentFunction } from './processPaymentFunction';
|
|
969
|
+
import { sendConfirmationFunction } from './sendConfirmationFunction';
|
|
970
|
+
|
|
971
|
+
export const orderMainWorkflow = (container: Container, inngest: Inngest) =>
|
|
972
|
+
inngest.createFunction(
|
|
973
|
+
{
|
|
974
|
+
id: WorkflowNamespace.ORDER_MGMT_MAIN_WORKFLOW,
|
|
975
|
+
name: 'Order Processing Workflow',
|
|
976
|
+
},
|
|
977
|
+
{
|
|
978
|
+
event: WorkflowNamespace.ORDER_MGMT_MAIN_EVENT,
|
|
979
|
+
},
|
|
980
|
+
async ({ event, step }) => {
|
|
981
|
+
const { userId, items, shippingAddress, paymentDetails } = event.data;
|
|
982
|
+
|
|
983
|
+
// Step 1: Create the order
|
|
984
|
+
const orderResult = await step.invoke(WorkflowNamespace.ORDER_MGMT_CREATE_ORDER, {
|
|
985
|
+
function: createOrderFunction(container, inngest),
|
|
986
|
+
data: { userId, items, shippingAddress },
|
|
987
|
+
});
|
|
988
|
+
|
|
989
|
+
// Step 2: Process payment
|
|
990
|
+
const paymentResult = await step.invoke(WorkflowNamespace.ORDER_MGMT_PROCESS_PAYMENT, {
|
|
991
|
+
function: processPaymentFunction(container, inngest),
|
|
992
|
+
data: {
|
|
993
|
+
orderId: orderResult.orderId,
|
|
994
|
+
paymentDetails,
|
|
995
|
+
},
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
// Step 3: Send confirmation
|
|
999
|
+
const confirmationResult = await step.invoke(WorkflowNamespace.ORDER_MGMT_SEND_CONFIRMATION, {
|
|
1000
|
+
function: sendConfirmationFunction(container, inngest),
|
|
1001
|
+
data: {
|
|
1002
|
+
orderId: orderResult.orderId,
|
|
1003
|
+
userId,
|
|
1004
|
+
total: orderResult.total,
|
|
1005
|
+
},
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
return {
|
|
1009
|
+
status: 'workflow-completed',
|
|
1010
|
+
orderId: orderResult.orderId,
|
|
1011
|
+
paymentId: paymentResult.paymentId,
|
|
1012
|
+
confirmationSent: confirmationResult.sent,
|
|
1013
|
+
};
|
|
1014
|
+
},
|
|
1015
|
+
);
|
|
1016
|
+
```
|
|
1017
|
+
|
|
1018
|
+
#### Step 4: Functions Factory
|
|
1019
|
+
|
|
1020
|
+
**File**: `src/modules/order/inngest/functions.ts`
|
|
1021
|
+
|
|
1022
|
+
```typescript
|
|
1023
|
+
import { Container } from 'inversify';
|
|
1024
|
+
import { Inngest } from 'inngest';
|
|
1025
|
+
import { createOrderFunction } from './createOrderFunction';
|
|
1026
|
+
import { processPaymentFunction } from './processPaymentFunction';
|
|
1027
|
+
import { sendConfirmationFunction } from './sendConfirmationFunction';
|
|
1028
|
+
import { updateInventoryFunction } from './updateInventoryFunction';
|
|
1029
|
+
import { orderMainWorkflow } from './mainWorkflow';
|
|
1030
|
+
|
|
1031
|
+
export const inngestFunctionsFactory = (args: { container: Container; inngest: Inngest }) => [
|
|
1032
|
+
// Individual functions
|
|
1033
|
+
createOrderFunction(args.container, args.inngest),
|
|
1034
|
+
processPaymentFunction(args.container, args.inngest),
|
|
1035
|
+
sendConfirmationFunction(args.container, args.inngest),
|
|
1036
|
+
updateInventoryFunction(args.container, args.inngest),
|
|
1037
|
+
|
|
1038
|
+
// Main orchestrator
|
|
1039
|
+
orderMainWorkflow(args.container, args.inngest),
|
|
1040
|
+
];
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
**File**: `src/modules/order/inngest/index.ts`
|
|
1044
|
+
|
|
1045
|
+
```typescript
|
|
1046
|
+
export { inngestFunctionsFactory } from './functions';
|
|
1047
|
+
```
|
|
1048
|
+
|
|
1049
|
+
#### Step 5: Feature Module
|
|
1050
|
+
|
|
1051
|
+
**File**: `src/modules/order/module.ts`
|
|
1052
|
+
|
|
1053
|
+
```typescript
|
|
1054
|
+
import { Feature } from '@common-stack/server-core';
|
|
1055
|
+
import { inngestFunctionsFactory } from './inngest';
|
|
1056
|
+
import { orderContainerModule } from './container';
|
|
1057
|
+
import { schema, resolver } from './graphql';
|
|
1058
|
+
|
|
1059
|
+
export default new Feature({
|
|
1060
|
+
schema,
|
|
1061
|
+
createResolversFunc: resolver,
|
|
1062
|
+
createContainerFunc: [orderContainerModule],
|
|
1063
|
+
|
|
1064
|
+
// Register Inngest functions
|
|
1065
|
+
inngestFunctions: [({ container, inngest }) => inngestFunctionsFactory({ container, inngest })],
|
|
1066
|
+
});
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
#### Step 6: Service Integration
|
|
1070
|
+
|
|
1071
|
+
**File**: `src/modules/order/services/OrderService.ts`
|
|
1072
|
+
|
|
1073
|
+
```typescript
|
|
1074
|
+
import { injectable, inject } from 'inversify';
|
|
1075
|
+
import type { Inngest } from 'inngest';
|
|
1076
|
+
import { CommonType } from '@common-stack/core';
|
|
1077
|
+
import { WorkflowNamespace, SERVER_TYPES } from 'common/server';
|
|
1078
|
+
|
|
1079
|
+
@injectable()
|
|
1080
|
+
export class OrderService implements IOrderService {
|
|
1081
|
+
constructor(
|
|
1082
|
+
@inject(SERVER_TYPES.OrderRepository)
|
|
1083
|
+
private readonly orderRepository: IOrderRepository,
|
|
1084
|
+
|
|
1085
|
+
@inject(CommonType.INNGEST_CLIENT)
|
|
1086
|
+
private readonly inngestClient: Inngest,
|
|
1087
|
+
|
|
1088
|
+
@inject('Logger')
|
|
1089
|
+
private readonly logger: Logger,
|
|
1090
|
+
) {}
|
|
1091
|
+
|
|
1092
|
+
async createOrder(input: ICreateOrderInput): Promise<IOrderResponse> {
|
|
1093
|
+
// Trigger the main workflow
|
|
1094
|
+
const { id: eventId } = await this.inngestClient.send({
|
|
1095
|
+
name: WorkflowNamespace.ORDER_MGMT_MAIN_EVENT,
|
|
1096
|
+
data: {
|
|
1097
|
+
userId: input.userId,
|
|
1098
|
+
items: input.items,
|
|
1099
|
+
shippingAddress: input.shippingAddress,
|
|
1100
|
+
paymentDetails: input.paymentDetails,
|
|
1101
|
+
},
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
this.logger.info(`Order workflow triggered: ${eventId}`);
|
|
1105
|
+
|
|
1106
|
+
return {
|
|
1107
|
+
status: 'processing',
|
|
1108
|
+
workflowId: eventId,
|
|
1109
|
+
message: 'Order is being processed',
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
---
|
|
1116
|
+
|
|
1117
|
+
## 11. Troubleshooting
|
|
1118
|
+
|
|
1119
|
+
### 11.1 Common Issues
|
|
1120
|
+
|
|
1121
|
+
#### Functions Not Loading
|
|
1122
|
+
|
|
1123
|
+
```bash
|
|
1124
|
+
# Check if template is registered in package.json
|
|
1125
|
+
cat packages-modules/{module}/server/package.json | grep WorkflowNamespace
|
|
1126
|
+
|
|
1127
|
+
# Regenerate common module
|
|
1128
|
+
yarn regenerateGraphql && yarn generateGraphql
|
|
1129
|
+
|
|
1130
|
+
# Verify build
|
|
1131
|
+
lerna run build --scope=common
|
|
1132
|
+
```
|
|
1133
|
+
|
|
1134
|
+
#### Import Errors for WorkflowNamespace
|
|
1135
|
+
|
|
1136
|
+
```typescript
|
|
1137
|
+
// ✅ CORRECT import path
|
|
1138
|
+
import { WorkflowNamespace } from 'common/server';
|
|
1139
|
+
|
|
1140
|
+
// ❌ WRONG - Don't import from common directly for server constants
|
|
1141
|
+
import { WorkflowNamespace } from 'common';
|
|
1142
|
+
```
|
|
1143
|
+
|
|
1144
|
+
#### Container Service Not Found
|
|
1145
|
+
|
|
1146
|
+
```typescript
|
|
1147
|
+
// Ensure service is bound in container module
|
|
1148
|
+
container.bind(SERVER_TYPES.MyService).to(MyService);
|
|
1149
|
+
|
|
1150
|
+
// Check binding identifier matches
|
|
1151
|
+
const service = container.get<IMyService>(SERVER_TYPES.MyService);
|
|
1152
|
+
```
|
|
1153
|
+
|
|
1154
|
+
#### Events Not Triggering
|
|
1155
|
+
|
|
1156
|
+
1. Check Inngest dev server is running
|
|
1157
|
+
2. Verify event name matches exactly
|
|
1158
|
+
3. Check `/api/inngest` endpoint is registered
|
|
1159
|
+
4. Review server logs for errors
|
|
1160
|
+
|
|
1161
|
+
### 11.2 Debug Commands
|
|
1162
|
+
|
|
1163
|
+
```bash
|
|
1164
|
+
# Check common module build
|
|
1165
|
+
lerna run build --scope=common
|
|
1166
|
+
|
|
1167
|
+
# Validate TypeScript
|
|
1168
|
+
npx tsc --noEmit
|
|
1169
|
+
|
|
1170
|
+
# Check for lint errors
|
|
1171
|
+
npm run lint
|
|
1172
|
+
|
|
1173
|
+
# Start Inngest dev server
|
|
1174
|
+
npx inngest-cli dev
|
|
1175
|
+
|
|
1176
|
+
# Check registered functions
|
|
1177
|
+
curl http://localhost:3000/api/inngest
|
|
1178
|
+
```
|
|
1179
|
+
|
|
1180
|
+
### 11.3 Validation Checklist
|
|
1181
|
+
|
|
1182
|
+
Before deploying:
|
|
1183
|
+
|
|
1184
|
+
- [ ] WorkflowNamespace template created in correct location
|
|
1185
|
+
- [ ] Template registered in `package.json` under `cdecode.common.constants`
|
|
1186
|
+
- [ ] Common module regenerated (`yarn regenerateGraphql && yarn generateGraphql`)
|
|
1187
|
+
- [ ] Function factory created and exports array of functions
|
|
1188
|
+
- [ ] Factory exported from `inngest/index.ts`
|
|
1189
|
+
- [ ] Feature module updated with `inngestFunctions` array
|
|
1190
|
+
- [ ] All event names use `WorkflowNamespace` constants
|
|
1191
|
+
- [ ] No TypeScript/ESLint errors
|
|
1192
|
+
- [ ] Functions tested in Inngest dev server
|
|
1193
|
+
|
|
1194
|
+
---
|
|
1195
|
+
|
|
1196
|
+
## Quick Reference Card
|
|
1197
|
+
|
|
1198
|
+
### Create New Function Checklist
|
|
1199
|
+
|
|
1200
|
+
1. **Add to WorkflowNamespace template**:
|
|
1201
|
+
- Function ID: `{PREFIX}_ACTION: '{prefix}-action'`
|
|
1202
|
+
- Event: `{PREFIX}_ACTION_EVENT: '{prefix}/action-trigger'`
|
|
1203
|
+
|
|
1204
|
+
2. **Create function file**: `{action}Function.ts`
|
|
1205
|
+
|
|
1206
|
+
3. **Add to factory**: `functions.ts`
|
|
1207
|
+
|
|
1208
|
+
4. **Regenerate**: `yarn regenerateGraphql && yarn generateGraphql`
|
|
1209
|
+
|
|
1210
|
+
### Function Signature
|
|
1211
|
+
|
|
1212
|
+
```typescript
|
|
1213
|
+
// Without container
|
|
1214
|
+
export const fn = (inngest: Inngest) => inngest.createFunction(...);
|
|
1215
|
+
|
|
1216
|
+
// With container
|
|
1217
|
+
export const fn = (container: Container, inngest: Inngest) => inngest.createFunction(...);
|
|
1218
|
+
```
|
|
1219
|
+
|
|
1220
|
+
### Feature Registration
|
|
1221
|
+
|
|
1222
|
+
```typescript
|
|
1223
|
+
inngestFunctions: [({ container, inngest }) => inngestFunctionsFactory({ container, inngest })];
|
|
1224
|
+
```
|
|
1225
|
+
|
|
1226
|
+
### Trigger from Service
|
|
1227
|
+
|
|
1228
|
+
```typescript
|
|
1229
|
+
await this.inngestClient.send({
|
|
1230
|
+
name: WorkflowNamespace.EVENT_NAME,
|
|
1231
|
+
data: {
|
|
1232
|
+
/* your data */
|
|
1233
|
+
},
|
|
1234
|
+
});
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
---
|
|
1238
|
+
|
|
1239
|
+
**Version**: 1.0.0
|
|
1240
|
+
**Last Updated**: December 2024
|
|
1241
|
+
**Maintainer**: AdminIDE Stack Team
|