@nocobase/app-template-default 0.0.0-stage → 1.0.0-beta.57

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.
Files changed (250) hide show
  1. package/.cursor/mcp.json +8 -0
  2. package/.mcp.json +8 -0
  3. package/.prettierignore +20 -0
  4. package/.vscode/mcp.json +8 -0
  5. package/AGENTS.md +432 -0
  6. package/CLAUDE.md +9 -0
  7. package/Dockerfile +132 -0
  8. package/Dockerfile.dockerignore +45 -0
  9. package/README.MD +481 -0
  10. package/cli/plugins.ts +14 -0
  11. package/client/agent-annotations-host.ts +19 -0
  12. package/client/app.ts +38 -0
  13. package/client/components/back-button.tsx +49 -0
  14. package/client/components/breadcrumbs.tsx +167 -0
  15. package/client/components/inbox-badge.ts +49 -0
  16. package/client/components/inbox-button.tsx +132 -0
  17. package/client/components/inbox-header-button.tsx +25 -0
  18. package/client/components/loading.tsx +35 -0
  19. package/client/components/page-container.tsx +24 -0
  20. package/client/components/page-header.tsx +33 -0
  21. package/client/components/route-child-page.tsx +121 -0
  22. package/client/components/route-dialog.tsx +10 -0
  23. package/client/components/route-drawer.tsx +10 -0
  24. package/client/components/route-overlay.tsx +190 -0
  25. package/client/components/ui/alert.tsx +75 -0
  26. package/client/components/ui/badge.tsx +51 -0
  27. package/client/components/ui/breadcrumb.tsx +121 -0
  28. package/client/components/ui/button.tsx +58 -0
  29. package/client/components/ui/collapsible.tsx +19 -0
  30. package/client/components/ui/context-menu.tsx +271 -0
  31. package/client/components/ui/dialog.tsx +160 -0
  32. package/client/components/ui/dropdown-menu.tsx +270 -0
  33. package/client/components/ui/empty.tsx +103 -0
  34. package/client/components/ui/field.tsx +236 -0
  35. package/client/components/ui/input-group.tsx +158 -0
  36. package/client/components/ui/input.tsx +20 -0
  37. package/client/components/ui/kbd.tsx +26 -0
  38. package/client/components/ui/label.tsx +18 -0
  39. package/client/components/ui/popover.tsx +89 -0
  40. package/client/components/ui/select.tsx +200 -0
  41. package/client/components/ui/separator.tsx +22 -0
  42. package/client/components/ui/sheet.tsx +137 -0
  43. package/client/components/ui/sidebar.tsx +723 -0
  44. package/client/components/ui/skeleton.tsx +13 -0
  45. package/client/components/ui/spinner.tsx +20 -0
  46. package/client/components/ui/tabs.tsx +79 -0
  47. package/client/components/ui/textarea.tsx +17 -0
  48. package/client/components/ui/toast.tsx +231 -0
  49. package/client/components/ui/tooltip.tsx +63 -0
  50. package/client/components/use-route-overlay.ts +26 -0
  51. package/client/config/api.ts +13 -0
  52. package/client/config/app.ts +8 -0
  53. package/client/config/auth.ts +18 -0
  54. package/client/config/index.ts +17 -0
  55. package/client/extensions/nocobase-auth-forms/field-props.ts +13 -0
  56. package/client/extensions/nocobase-auth-forms/form-parts.tsx +101 -0
  57. package/client/extensions/nocobase-auth-forms/password-input.tsx +41 -0
  58. package/client/extensions/nocobase-auth-forms/password-login-form.tsx +123 -0
  59. package/client/extensions/nocobase-auth-forms/password-registration-form.tsx +193 -0
  60. package/client/extensions/nocobase-auth-forms/password-reset-form.tsx +132 -0
  61. package/client/extensions/nocobase-auth-forms/password-reset-request-form.tsx +99 -0
  62. package/client/extensions/nocobase-auth-methods/auth-methods.tsx +170 -0
  63. package/client/extensions/nocobase-auth-split-layout/auth-split-layout.tsx +126 -0
  64. package/client/extensions/nocobase-device-approval/device-approval.tsx +277 -0
  65. package/client/extensions/nocobase-device-approval/locales/en-US.ts +55 -0
  66. package/client/extensions/nocobase-device-approval/locales/zh-CN.ts +27 -0
  67. package/client/extensions/nocobase-device-approval/use-device-approval.ts +176 -0
  68. package/client/extensions/nocobase-file-component-ui/README.md +13 -0
  69. package/client/extensions/nocobase-file-component-ui/components/file-list.tsx +147 -0
  70. package/client/extensions/nocobase-file-component-ui/components/file-preview-dialog.tsx +263 -0
  71. package/client/extensions/nocobase-file-component-ui/components/file-preview-field.tsx +68 -0
  72. package/client/extensions/nocobase-file-component-ui/components/file-thumbnail.tsx +73 -0
  73. package/client/extensions/nocobase-file-component-ui/components/file-upload-field.tsx +386 -0
  74. package/client/extensions/nocobase-file-component-ui/components/previewers/file-preview-content.tsx +255 -0
  75. package/client/extensions/nocobase-file-component-ui/components/previewers/office-open-xml-preview.tsx +226 -0
  76. package/client/extensions/nocobase-file-component-ui/index.ts +8 -0
  77. package/client/extensions/nocobase-file-component-ui/lib/file-preview.ts +194 -0
  78. package/client/extensions/nocobase-file-component-ui/lib/file-url.ts +22 -0
  79. package/client/extensions/nocobase-file-component-ui/lib/message-key.ts +18 -0
  80. package/client/extensions/nocobase-file-component-ui/types.ts +69 -0
  81. package/client/extensions/nocobase-inbox/decision-actions-bar.tsx +140 -0
  82. package/client/extensions/nocobase-inbox/frame.ts +31 -0
  83. package/client/extensions/nocobase-inbox/inbox-actions.ts +21 -0
  84. package/client/extensions/nocobase-inbox/inbox-detail.tsx +386 -0
  85. package/client/extensions/nocobase-inbox/inbox-item.tsx +274 -0
  86. package/client/extensions/nocobase-inbox/inbox-list.tsx +433 -0
  87. package/client/extensions/nocobase-inbox/inbox-page.tsx +545 -0
  88. package/client/extensions/nocobase-inbox/locales/en-US.ts +111 -0
  89. package/client/extensions/nocobase-inbox/locales/zh-CN.ts +57 -0
  90. package/client/extensions/nocobase-inbox/model.ts +428 -0
  91. package/client/extensions/nocobase-inbox/registry-scope.tsx +49 -0
  92. package/client/extensions/nocobase-inbox/registry.ts +303 -0
  93. package/client/extensions/nocobase-inbox/source.ts +117 -0
  94. package/client/hooks/use-mobile.ts +21 -0
  95. package/client/index.tsx +60 -0
  96. package/client/layouts/app-layout.tsx +105 -0
  97. package/client/layouts/components/app-brand.tsx +49 -0
  98. package/client/layouts/components/app-sidebar.tsx +196 -0
  99. package/client/layouts/components/header-actions.tsx +50 -0
  100. package/client/layouts/components/language-switcher.tsx +95 -0
  101. package/client/layouts/components/layout-header.tsx +17 -0
  102. package/client/layouts/components/navigation-menu.tsx +411 -0
  103. package/client/layouts/components/sidebar-footer.tsx +107 -0
  104. package/client/layouts/components/surface-empty.tsx +35 -0
  105. package/client/layouts/components/user-menu.tsx +127 -0
  106. package/client/layouts/index.ts +2 -0
  107. package/client/layouts/settings-layout.tsx +172 -0
  108. package/client/layouts/use-sidebar-preference.ts +57 -0
  109. package/client/lib/constants.ts +5 -0
  110. package/client/lib/toaster.ts +56 -0
  111. package/client/lib/utils.ts +1 -0
  112. package/client/locales/en-US.ts +178 -0
  113. package/client/locales/index.ts +9 -0
  114. package/client/locales/zh-CN.ts +161 -0
  115. package/client/pages/auth/device.tsx +41 -0
  116. package/client/pages/auth/forgot-password.tsx +39 -0
  117. package/client/pages/auth/login.tsx +66 -0
  118. package/client/pages/auth/register.tsx +46 -0
  119. package/client/pages/auth/reset-password.tsx +38 -0
  120. package/client/pages/auth/shared.tsx +111 -0
  121. package/client/pages/home.tsx +16 -0
  122. package/client/pages/inbox.tsx +12 -0
  123. package/client/plugins.ts +41 -0
  124. package/client/react-providers.ts +27 -0
  125. package/client/route-overrides.ts +9 -0
  126. package/client/routes.ts +75 -0
  127. package/client/routing/app-router.tsx +127 -0
  128. package/client/routing/client-route.tsx +129 -0
  129. package/client/routing/route-context.tsx +85 -0
  130. package/client/routing/route-navigation.ts +153 -0
  131. package/client/routing/route-tree.tsx +42 -0
  132. package/client/routing/standalone-page-layout.tsx +15 -0
  133. package/client/runtime.ts +26 -0
  134. package/client/service-provider.ts +40 -0
  135. package/client/source-extensions.ts +19 -0
  136. package/client/startup.tsx +22 -0
  137. package/client/styles.css +122 -0
  138. package/client/theme/index.ts +4 -0
  139. package/client/theme/theme-context.ts +12 -0
  140. package/client/theme/theme-preferences.ts +84 -0
  141. package/client/theme/theme-presets.ts +7 -0
  142. package/client/theme/theme-provider.tsx +106 -0
  143. package/client/theme/theme-settings.tsx +176 -0
  144. package/client/theme/themes/compact.css +140 -0
  145. package/client/theme/themes/default.css +117 -0
  146. package/client/vite-env.d.ts +5 -0
  147. package/components.json +27 -0
  148. package/config.example.yml +172 -0
  149. package/database/main/migrations/.gitkeep +0 -0
  150. package/database/main/migrations/202610060001_create_device_code.ts +37 -0
  151. package/database/main/seeds/.gitkeep +0 -0
  152. package/database/tsconfig.json +4 -0
  153. package/ecosystem.config.js +35 -0
  154. package/eslint.config.js +24 -0
  155. package/index.html +100 -0
  156. package/package.json +200 -3
  157. package/playwright.config.ts +10 -0
  158. package/public/assets/favicon.ico +0 -0
  159. package/public/assets/logo-dark.png +0 -0
  160. package/public/assets/logo-mark-dark.png +0 -0
  161. package/public/assets/logo-mark.png +0 -0
  162. package/public/assets/logo.png +0 -0
  163. package/server/app.ts +50 -0
  164. package/server/config/ai.ts +27 -0
  165. package/server/config/api.ts +8 -0
  166. package/server/config/app.ts +40 -0
  167. package/server/config/auth.ts +36 -0
  168. package/server/config/authorization.ts +18 -0
  169. package/server/config/caching.ts +21 -0
  170. package/server/config/database.ts +22 -0
  171. package/server/config/drive.ts +30 -0
  172. package/server/config/i18n.ts +17 -0
  173. package/server/config/index.ts +73 -0
  174. package/server/config/jobs.ts +27 -0
  175. package/server/config/logging.ts +23 -0
  176. package/server/config/notification.ts +11 -0
  177. package/server/config/queue.ts +28 -0
  178. package/server/config/scheduler.ts +23 -0
  179. package/server/config/secrets.ts +10 -0
  180. package/server/config/server.ts +26 -0
  181. package/server/config/session.ts +60 -0
  182. package/server/config/snowflake.ts +21 -0
  183. package/server/config/spa.ts +24 -0
  184. package/server/config/users.ts +11 -0
  185. package/server/config/workflow.ts +24 -0
  186. package/server/config.ts +24 -0
  187. package/server/embedded.ts +23 -0
  188. package/server/locales/en-US.ts +10 -0
  189. package/server/locales/index.ts +10 -0
  190. package/server/locales/zh-CN.ts +5 -0
  191. package/server/plugins.ts +41 -0
  192. package/server/providers/index.ts +5 -0
  193. package/server/routes/index.ts +6 -0
  194. package/server/runtime.ts +24 -0
  195. package/server/standalone.ts +29 -0
  196. package/server/tsconfig.json +4 -0
  197. package/tailwind.config.mjs +59 -0
  198. package/tests/components/app-layout-routes.test.tsx +132 -0
  199. package/tests/components/app-title.test.tsx +57 -0
  200. package/tests/components/auth-i18n.test.tsx +87 -0
  201. package/tests/components/back-button.test.tsx +80 -0
  202. package/tests/components/file-preview.test.tsx +101 -0
  203. package/tests/components/header-hover.test.tsx +87 -0
  204. package/tests/components/inbox.test.tsx +139 -0
  205. package/tests/components/language-switcher.test.tsx +298 -0
  206. package/tests/components/layout-containers.test.tsx +15 -0
  207. package/tests/components/layout-i18n.test.tsx +187 -0
  208. package/tests/components/loading.test.tsx +25 -0
  209. package/tests/components/navigation-menu.test.tsx +355 -0
  210. package/tests/components/page-harness.test.tsx +318 -0
  211. package/tests/components/primitive-labels.test.tsx +80 -0
  212. package/tests/components/sidebar-permissions.test.tsx +110 -0
  213. package/tests/components/sidebar-preference.test.tsx +42 -0
  214. package/tests/fixtures/theme-tokens.html +12 -0
  215. package/tests/fixtures/theme-tokens.tsx +111 -0
  216. package/tests/logic/account-permissions.test.tsx +204 -0
  217. package/tests/logic/app-locale-coverage.test.ts +136 -0
  218. package/tests/logic/app-server.test.ts +1589 -0
  219. package/tests/logic/asset-url-build.test.ts +106 -0
  220. package/tests/logic/client-auth.test.tsx +122 -0
  221. package/tests/logic/client-plugin-registry.test.ts +63 -0
  222. package/tests/logic/client-route-recovery.test.tsx +80 -0
  223. package/tests/logic/client-routes.test.ts +126 -0
  224. package/tests/logic/client-runtime.test.ts +112 -0
  225. package/tests/logic/client-settings.test.tsx +841 -0
  226. package/tests/logic/client-shell.test.tsx +466 -0
  227. package/tests/logic/client-theme.test.tsx +441 -0
  228. package/tests/logic/config.test.ts +197 -0
  229. package/tests/logic/dev-client-watch.test.ts +108 -0
  230. package/tests/logic/dev-routes-production-build.test.ts +168 -0
  231. package/tests/logic/device-code-migration.test.ts +70 -0
  232. package/tests/logic/lifecycle.test.ts +221 -0
  233. package/tests/logic/plugin-commands.test.ts +69 -0
  234. package/tests/logic/plugin-page-authz.test.ts +76 -0
  235. package/tests/logic/route-navigation.test.ts +66 -0
  236. package/tests/logic/route-overlay.test.tsx +353 -0
  237. package/tests/logic/server-imports.test.ts +88 -0
  238. package/tests/logic/tailwind-sources.test.ts +151 -0
  239. package/tests/logic/template-package-name.test.ts +88 -0
  240. package/tests/logic/theme-preferences.test.ts +86 -0
  241. package/tests/logic/theme-tokens.test.ts +248 -0
  242. package/tests/logic/toaster.test.tsx +108 -0
  243. package/tests/logic/user-menu-sign-out.test.tsx +98 -0
  244. package/tests/setup/client-config.ts +27 -0
  245. package/tsconfig.json +11 -0
  246. package/tsconfig.node.json +12 -0
  247. package/tsconfig.server.json +19 -0
  248. package/vite.config.ts +92 -0
  249. package/vitest.config.ts +37 -0
  250. package/README.md +0 -3
@@ -0,0 +1,27 @@
1
+ import type { AppConfigFactory } from '@nocobase/app-server/config';
2
+ import {
3
+ defineAIConfig,
4
+ type AIApplicationConfig,
5
+ } from '@nocobase/app-plugin-ai-employee/server/config';
6
+
7
+ const ai: AppConfigFactory<AIApplicationConfig> = defineAIConfig({
8
+ // Map a secret onto the field of one service it sets, keyed by that
9
+ // service's name, such as
10
+ // `OPENAI_API_KEY: envString('llmServices.openai.options.apiKey')` or
11
+ // `GITHUB_MCP_TOKEN: envString('mcpServers.github.headers.Authorization')`.
12
+ env: {},
13
+ defaults: () => ({
14
+ storage: {},
15
+ aiEmployee: { storage: {} },
16
+ aiKnowledgeBase: {
17
+ storage: {},
18
+ vectorDatabases: [],
19
+ manifests: [],
20
+ },
21
+ llmServices: {},
22
+ skills: { paths: [] },
23
+ mcpServers: {},
24
+ }),
25
+ });
26
+
27
+ export default ai;
@@ -0,0 +1,8 @@
1
+ import type { AppConfigFactory } from '@nocobase/app-server/config';
2
+ import { defineApiConfig, type ApiConfig } from '@nocobase/app-server/router';
3
+
4
+ // Limits every /api request meets ahead of its route: bodyLimit, timeout and rateLimit. Each is off until config.yml
5
+ // sets it; see the commented api section in config.example.yml. API_BODY_LIMIT and API_TIMEOUT set the first two.
6
+ const api: AppConfigFactory<ApiConfig> = defineApiConfig();
7
+
8
+ export default api;
@@ -0,0 +1,40 @@
1
+ import {
2
+ defineAppConfig,
3
+ envBoolean,
4
+ envString,
5
+ type AppConfigFactory,
6
+ } from '@nocobase/app-server/config';
7
+ import type { AppIdentityConfig } from '@nocobase/app-server/config';
8
+ import {
9
+ joinBasePath,
10
+ normalizeBasePath,
11
+ resolveAppNameFromBasePath,
12
+ } from '@nocobase/app-server/support';
13
+
14
+ const app: AppConfigFactory<AppIdentityConfig> = defineAppConfig({
15
+ env: {
16
+ APP_PUBLIC_ORIGIN: envString('publicOrigin', {
17
+ description:
18
+ 'The origin browsers reach the application at, such as https://apps.example.com, for callbacks and redirects.',
19
+ required: false,
20
+ }),
21
+ APP_SAMPLE_DATA: envBoolean('sampleData', {
22
+ description:
23
+ 'Load sample data while the database is first installed: seeds declared with sample: true and sampleDataToken registrations.',
24
+ required: false,
25
+ firstStartOnly: true,
26
+ }),
27
+ },
28
+ defaults: (runtime) => {
29
+ const { routing } = runtime;
30
+ const publicBasePath = normalizeBasePath(routing.publicBasePath || '/main');
31
+ return {
32
+ name: routing.name || resolveAppNameFromBasePath(publicBasePath, 'main'),
33
+ publicBasePath,
34
+ internalBasePath: routing.internalBasePath,
35
+ publicApiUrl: joinBasePath(publicBasePath, '/api'),
36
+ };
37
+ },
38
+ });
39
+
40
+ export default app;
@@ -0,0 +1,36 @@
1
+ import type { AppConfigFactory } from '@nocobase/app-server/config';
2
+ import { apiKey } from '@nocobase/app-plugin-api-keys/server';
3
+ import {
4
+ defineAuthConfig,
5
+ type AuthConfig,
6
+ } from '@nocobase/app-plugin-authentication/server';
7
+ import { bearer, deviceAuthorization, username } from 'better-auth/plugins';
8
+
9
+ /**
10
+ * The command-line clients that may sign in through the browser (`deviceAuthorization()`): `nocobase-cli`, the id
11
+ * `@nocobase/app-cli-client` sends unless a branded CLI names its own. Add the id of any other CLI that should sign in.
12
+ */
13
+ const CLI_CLIENT_IDS: readonly string[] = ['nocobase-cli'];
14
+
15
+ const auth: AppConfigFactory<AuthConfig> = defineAuthConfig({
16
+ defaults: {
17
+ plugins: [
18
+ username({ displayUsername: false }),
19
+ apiKey(),
20
+ // A CLI signs in through the browser (RFC 8628): it shows a code the person approves on `/device`, below the
21
+ // application's base path, and receives a session token it sends as `Authorization: Bearer` (`bearer()`).
22
+ deviceAuthorization({
23
+ verificationUri: '/device',
24
+ expiresIn: '10m',
25
+ interval: '5s',
26
+ validateClient: (clientId) => CLI_CLIENT_IDS.includes(clientId),
27
+ }),
28
+ bearer(),
29
+ ],
30
+ emailAndPassword: { enabled: true, autoSignIn: false },
31
+ session: { storeSessionInDatabase: true },
32
+ account: { encryptOAuthTokens: true },
33
+ },
34
+ });
35
+
36
+ export default auth;
@@ -0,0 +1,18 @@
1
+ import { defaultAccess } from '@nocobase/app-plugin-authz-default-access/server';
2
+ import { sharingRules } from '@nocobase/app-plugin-authz-sharing-rules/server';
3
+ import { restrictionRules } from '@nocobase/app-plugin-authz-restriction-rules/server';
4
+ import {
5
+ defineAppConfig,
6
+ type AppConfigFactory,
7
+ } from '@nocobase/app-server/config';
8
+ import { type AuthorizationConfig } from '@nocobase/app-plugin-authorization/server';
9
+
10
+ // Permission sets, database, pages, settings, composites and workspace placement are built in.
11
+ const authorization: AppConfigFactory<AuthorizationConfig> = defineAppConfig(
12
+ (_runtime) => ({
13
+ permissionSets: { rootSet: 'root', defaultSet: 'member' },
14
+ plugins: [defaultAccess(), sharingRules(), restrictionRules()],
15
+ }),
16
+ );
17
+
18
+ export default authorization;
@@ -0,0 +1,21 @@
1
+ import {
2
+ defineAppConfig,
3
+ type AppConfigFactory,
4
+ } from '@nocobase/app-server/config';
5
+ import type { CachingConfig } from '@nocobase/caching';
6
+
7
+ const caching: AppConfigFactory<CachingConfig> = defineAppConfig(
8
+ (_runtime) => ({
9
+ default: 'memory',
10
+ providers: {
11
+ memory: {
12
+ driver: 'memory',
13
+ defaultTtl: '5m',
14
+ maxSize: 2_000,
15
+ useClone: true,
16
+ },
17
+ },
18
+ }),
19
+ );
20
+
21
+ export default caching;
@@ -0,0 +1,22 @@
1
+ import {
2
+ connectionEnvironment,
3
+ defineAppDatabaseConfig,
4
+ } from '@nocobase/app-server/database';
5
+
6
+ /** Installed official drivers are loaded synchronously when first needed. */
7
+ export default defineAppDatabaseConfig(
8
+ ({ paths }) => ({
9
+ default: 'main',
10
+ connections: {
11
+ main: {
12
+ dialect: 'sqlite',
13
+ filename: paths.storage('database.sqlite'),
14
+ schemaManagement: 'managed',
15
+ debug: false,
16
+ },
17
+ },
18
+ }),
19
+ // DB_DIALECT, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD, DB_SSL and DB_FILENAME set the main
20
+ // connection. Another connection declares its own, such as connectionEnvironment('analytics', 'DB_ANALYTICS').
21
+ { env: connectionEnvironment('main') },
22
+ );
@@ -0,0 +1,30 @@
1
+ import {
2
+ defineAppConfig,
3
+ type AppConfigFactory,
4
+ } from '@nocobase/app-server/config';
5
+ import type { AppDriveConfig } from '@nocobase/drive';
6
+
7
+ const drive: AppConfigFactory<AppDriveConfig> = defineAppConfig(({ paths }) => {
8
+ const disks: AppDriveConfig['disks'] = {
9
+ local: {
10
+ driver: 'fs',
11
+ location: paths.storage(),
12
+ visibility: 'private',
13
+ },
14
+ s3: {
15
+ driver: 's3',
16
+ bucket: '',
17
+ region: 'us-east-1',
18
+ forcePathStyle: false,
19
+ supportsACL: true,
20
+ credentials: {},
21
+ visibility: 'private',
22
+ },
23
+ };
24
+ return {
25
+ default: 'local',
26
+ disks,
27
+ };
28
+ });
29
+
30
+ export default drive;
@@ -0,0 +1,17 @@
1
+ import {
2
+ defineAppConfig,
3
+ envString,
4
+ type AppConfigFactory,
5
+ } from '@nocobase/app-server/config';
6
+ import type { AppI18nConfig } from '@nocobase/app-server/i18n';
7
+
8
+ const i18n: AppConfigFactory<AppI18nConfig> = defineAppConfig({
9
+ defaults: { defaultLocale: 'en-US' },
10
+ env: {
11
+ APP_DEFAULT_LOCALE: envString('defaultLocale', {
12
+ description: 'The language the application starts in, such as zh-CN.',
13
+ }),
14
+ },
15
+ });
16
+
17
+ export default i18n;
@@ -0,0 +1,73 @@
1
+ import {
2
+ defaultAppConfigs,
3
+ type AppConfigFactory,
4
+ } from '@nocobase/app-server/config';
5
+ import auth from './auth.js';
6
+ import authorization from './authorization.js';
7
+ import notification from './notification.js';
8
+ import secrets from './secrets.js';
9
+ import session from './session.js';
10
+ import server from './server.js';
11
+ import spa from './spa.js';
12
+ import logging from './logging.js';
13
+ import drive from './drive.js';
14
+ import queue from './queue.js';
15
+ import jobs from './jobs.js';
16
+ import scheduler from './scheduler.js';
17
+ import caching from './caching.js';
18
+ import i18n from './i18n.js';
19
+ import app from './app.js';
20
+ import api from './api.js';
21
+ import database from './database.js';
22
+ import snowflake from './snowflake.js';
23
+ import ai from './ai.js';
24
+ import workflow from './workflow.js';
25
+ import users from './users.js';
26
+
27
+ const defaultConfigs: AppConfigFactory<{
28
+ auth: ReturnType<typeof auth>;
29
+ authorization: ReturnType<typeof authorization>;
30
+ notification: ReturnType<typeof notification>;
31
+ secrets: ReturnType<typeof secrets>;
32
+ session: ReturnType<typeof session>;
33
+ server: ReturnType<typeof server>;
34
+ spa: ReturnType<typeof spa>;
35
+ logging: ReturnType<typeof logging>;
36
+ drive: ReturnType<typeof drive>;
37
+ queue: ReturnType<typeof queue>;
38
+ jobs: ReturnType<typeof jobs>;
39
+ scheduler: ReturnType<typeof scheduler>;
40
+ caching: ReturnType<typeof caching>;
41
+ i18n: ReturnType<typeof i18n>;
42
+ app: ReturnType<typeof app>;
43
+ api: ReturnType<typeof api>;
44
+ database: ReturnType<typeof database>;
45
+ snowflake: ReturnType<typeof snowflake>;
46
+ ai: ReturnType<typeof ai>;
47
+ workflow: ReturnType<typeof workflow>;
48
+ users: ReturnType<typeof users>;
49
+ }> = defaultAppConfigs({
50
+ auth,
51
+ authorization,
52
+ notification,
53
+ secrets,
54
+ session,
55
+ server,
56
+ spa,
57
+ logging,
58
+ drive,
59
+ queue,
60
+ jobs,
61
+ scheduler,
62
+ caching,
63
+ i18n,
64
+ app,
65
+ api,
66
+ database,
67
+ snowflake,
68
+ ai,
69
+ workflow,
70
+ users,
71
+ });
72
+
73
+ export default defaultConfigs;
@@ -0,0 +1,27 @@
1
+ import {
2
+ defineAppConfig,
3
+ type AppConfigFactory,
4
+ } from '@nocobase/app-server/config';
5
+ import type { AppJobsConfig } from '@nocobase/app-server/jobs';
6
+
7
+ /**
8
+ * Configurations the jobs service can run on. None is the default: until `jobs.default` names one, executors
9
+ * run on the built-in memory adapter, which serves one process and writes its state under storage/jobs when the
10
+ * application stops, and which is reported at startup outside development. Name `memory` to keep that choice without
11
+ * the report, or `redis` to run any number of instances with each firing executed once.
12
+ */
13
+ const jobs: AppConfigFactory<AppJobsConfig> = defineAppConfig(({ paths }) => ({
14
+ memory: {
15
+ adapter: 'memory',
16
+ persistence: { path: paths.storage('jobs') },
17
+ },
18
+ redis: {
19
+ adapter: 'redis',
20
+ connection: { host: '127.0.0.1', port: 6379, db: 0 },
21
+ // Every firing leaves a finished job behind; keep the history bounded.
22
+ removeOnComplete: { count: 1000 },
23
+ removeOnFail: { age: 604_800 },
24
+ },
25
+ }));
26
+
27
+ export default jobs;
@@ -0,0 +1,23 @@
1
+ import {
2
+ defineAppConfig,
3
+ type AppConfigFactory,
4
+ } from '@nocobase/app-server/config';
5
+ import type { AppLoggingConfig } from '@nocobase/app-server/logging';
6
+
7
+ const logging: AppConfigFactory<AppLoggingConfig> = defineAppConfig(
8
+ (runtime) => ({
9
+ level: 'info',
10
+ file: {
11
+ enabled: true,
12
+ name: 'app',
13
+ retentionDays: 7,
14
+ maxFileSizeMB: 10,
15
+ maxTotalSizeMB: 500,
16
+ },
17
+ loggers: {
18
+ request: { file: { name: 'request' } },
19
+ },
20
+ console: { enabled: true, pretty: runtime.env.NODE_ENV !== 'production' },
21
+ }),
22
+ );
23
+ export default logging;
@@ -0,0 +1,11 @@
1
+ import {
2
+ defineAppConfig,
3
+ type AppConfigFactory,
4
+ } from '@nocobase/app-server/config';
5
+ import type { NotificationConfig } from '@nocobase/app-plugin-notification/server';
6
+
7
+ const notification: AppConfigFactory<NotificationConfig> = defineAppConfig(
8
+ (_runtime) => ({ channels: {} }),
9
+ );
10
+
11
+ export default notification;
@@ -0,0 +1,28 @@
1
+ import {
2
+ defineAppConfig,
3
+ type AppConfigFactory,
4
+ } from '@nocobase/app-server/config';
5
+ import type { AppQueueConfig } from '@nocobase/app-server/queue';
6
+
7
+ /**
8
+ * Configurations queues can run on. None is the default: until `queue.default` names one, queues run on the
9
+ * built-in memory configuration, which serves one process and writes its pending jobs under storage/queue when the
10
+ * application stops, and which is reported at startup outside development. Name `memory` to keep that choice without
11
+ * the report, or `redis` to share queues across instances.
12
+ */
13
+ const queue: AppConfigFactory<AppQueueConfig> = defineAppConfig(
14
+ ({ paths }) => ({
15
+ memory: {
16
+ adapter: 'inMemory',
17
+ persistence: { path: paths.storage('queue') },
18
+ },
19
+ redis: {
20
+ adapter: 'redis',
21
+ connection: { host: '127.0.0.1', port: 6379, db: 0 },
22
+ removeOnComplete: { count: 1000 },
23
+ removeOnFail: { age: 604_800 },
24
+ },
25
+ }),
26
+ );
27
+
28
+ export default queue;
@@ -0,0 +1,23 @@
1
+ import type { SchedulerConfig } from '@nocobase/app-plugin-scheduler/server';
2
+ import {
3
+ defineAppConfig,
4
+ envString,
5
+ type AppConfigFactory,
6
+ } from '@nocobase/app-server/config';
7
+
8
+ /**
9
+ * The Scheduler plugin's settings. `jobs` names the `jobs` configuration its schedules run on; left out, they follow
10
+ * `jobs.default` like every other consumer. A name that `jobs` does not define stops the application from starting.
11
+ */
12
+ const scheduler: AppConfigFactory<SchedulerConfig> = defineAppConfig({
13
+ env: {
14
+ SCHEDULER_JOBS: envString('jobs', {
15
+ description:
16
+ 'The jobs configuration scheduled jobs run on; jobs.default when unset.',
17
+ required: false,
18
+ }),
19
+ },
20
+ defaults: () => ({}),
21
+ });
22
+
23
+ export default scheduler;
@@ -0,0 +1,10 @@
1
+ import type { AppConfigFactory } from '@nocobase/app-server/config';
2
+ import {
3
+ defineSecretsConfig,
4
+ type SecretsConfig,
5
+ } from '@nocobase/app-server/secrets';
6
+
7
+ // The master keys, current first, come from config.yml or SECRETS_KEYS; nothing is defaulted here.
8
+ const secrets: AppConfigFactory<SecretsConfig> = defineSecretsConfig();
9
+
10
+ export default secrets;
@@ -0,0 +1,26 @@
1
+ import {
2
+ defineAppConfig,
3
+ envBoolean,
4
+ envInteger,
5
+ envString,
6
+ type AppConfigFactory,
7
+ } from '@nocobase/app-server/config';
8
+ import type { NodeServerConfig } from '@nocobase/app-server/node';
9
+
10
+ const server: AppConfigFactory<NodeServerConfig> = defineAppConfig({
11
+ defaults: { host: '127.0.0.1', port: 13000, startLog: true },
12
+ env: {
13
+ APP_SERVER_HOST: envString('host', {
14
+ description: 'The address the server listens on.',
15
+ }),
16
+ APP_SERVER_PORT: envInteger('port', {
17
+ description: 'The port the server listens on.',
18
+ }),
19
+ // `pnpm dev` sets it to false: it prints its own ready banner and public URL.
20
+ APP_SERVER_START_LOG: envBoolean('startLog', {
21
+ description: 'Whether the server logs its address once it is ready.',
22
+ }),
23
+ },
24
+ });
25
+
26
+ export default server;
@@ -0,0 +1,60 @@
1
+ import {
2
+ defineAppConfig,
3
+ envString,
4
+ type AppConfigFactory,
5
+ } from '@nocobase/app-server/config';
6
+ import type { AppSessionConfigInput } from '@nocobase/app-server/session';
7
+ import { normalizeBasePath } from '@nocobase/app-server/support';
8
+
9
+ const session: AppConfigFactory<AppSessionConfigInput> = defineAppConfig({
10
+ env: {
11
+ SESSION_SECRET: envString('secret', {
12
+ description:
13
+ 'The legacy session signing secret; keys are derived from SECRETS_KEYS when it is set.',
14
+ secret: true,
15
+ generate: 'secret',
16
+ }),
17
+ },
18
+ defaults: ({ paths, env, routing }) => ({
19
+ enabled: true,
20
+ default: 'memory',
21
+ cookie: {
22
+ name: 'nocobase_session',
23
+ // The application's own public base path, as `app.publicBasePath` resolves it: applications sharing an origin
24
+ // under different paths (`/crm`, `/acme`) each keep their own session cookie instead of overwriting one another's.
25
+ path: normalizeBasePath(routing.publicBasePath || '/main'),
26
+ secure: env.NODE_ENV === 'production',
27
+ httpOnly: true,
28
+ sameSite: 'lax' as const,
29
+ partitioned: false,
30
+ expireOnClose: false,
31
+ },
32
+ lifetime: {
33
+ absolute: '2h',
34
+ rolling: true,
35
+ },
36
+ previousSecrets: [],
37
+ gcLottery: { hits: 2, total: 100 },
38
+ stores: {
39
+ memory: {
40
+ driver: 'memory',
41
+ base: 'nocobase:session:',
42
+ },
43
+ fs: {
44
+ driver: 'fs',
45
+ base: paths.storage('sessions'),
46
+ },
47
+ redis: {
48
+ driver: 'redis',
49
+ host: '127.0.0.1',
50
+ port: 6379,
51
+ db: 0,
52
+ base: 'nocobase:session:',
53
+ tls: false,
54
+ },
55
+ null: { driver: 'null' },
56
+ },
57
+ }),
58
+ });
59
+
60
+ export default session;
@@ -0,0 +1,21 @@
1
+ import {
2
+ defineAppConfig,
3
+ envInteger,
4
+ type AppConfigFactory,
5
+ } from '@nocobase/app-server/config';
6
+ import type { SnowflakeIdGeneratorConfig } from '@nocobase/snowflake';
7
+ import { SNOWFLAKE_EPOCH_SECONDS } from '@nocobase/snowflake';
8
+
9
+ const snowflake: AppConfigFactory<SnowflakeIdGeneratorConfig> = defineAppConfig(
10
+ {
11
+ defaults: { workerId: 0, epoch: SNOWFLAKE_EPOCH_SECONDS },
12
+ env: {
13
+ SNOWFLAKE_WORKER_ID: envInteger('workerId', {
14
+ description:
15
+ 'A worker ID unique to each concurrently running instance, 0 to 1023.',
16
+ }),
17
+ },
18
+ },
19
+ );
20
+
21
+ export default snowflake;
@@ -0,0 +1,24 @@
1
+ import {
2
+ defineAppConfig,
3
+ type AppConfigFactory,
4
+ } from '@nocobase/app-server/config';
5
+ import type { SpaConfig } from '@nocobase/app-server/spa';
6
+
7
+ const spa: AppConfigFactory<SpaConfig> = defineAppConfig({
8
+ defaults: ({ paths }) => ({
9
+ indexPath: paths.client('index.html'),
10
+ }),
11
+ env: {
12
+ // The Vite dev server `pnpm dev` proxies to; `false` or `0` serves the built client instead.
13
+ APP_VITE_DEV_URL: {
14
+ path: 'viteDevUrl',
15
+ description:
16
+ 'The Vite dev server pnpm dev proxies the client to; false or 0 serves the built client.',
17
+ required: false,
18
+ parse: (value): string | null =>
19
+ value === 'false' || value === '0' ? null : value,
20
+ },
21
+ },
22
+ });
23
+
24
+ export default spa;
@@ -0,0 +1,11 @@
1
+ import type { AppConfigFactory } from '@nocobase/app-server/config';
2
+ import {
3
+ defineUsersConfig,
4
+ type UsersConfig,
5
+ } from '@nocobase/app-plugin-users/server/config';
6
+
7
+ // The initial administrator comes from config.yml (users.initialAdmin) or INITIAL_ADMIN_USERNAME, INITIAL_ADMIN_EMAIL
8
+ // and INITIAL_ADMIN_PASSWORD, read once while the user table is empty.
9
+ const users: AppConfigFactory<UsersConfig> = defineUsersConfig();
10
+
11
+ export default users;
@@ -0,0 +1,24 @@
1
+ import {
2
+ defineAppConfig,
3
+ type AppConfigFactory,
4
+ } from '@nocobase/app-server/config';
5
+ import type { WorkflowRuntimeConfig } from '@nocobase/app-plugin-workflow/server';
6
+ import { resolveWorkflowRuntimeConfig } from '@nocobase/app-plugin-workflow/server';
7
+
8
+ const workflow: AppConfigFactory<WorkflowRuntimeConfig> = defineAppConfig(
9
+ ({ paths, env }) =>
10
+ resolveWorkflowRuntimeConfig(
11
+ {
12
+ sourceRoot: paths.root('workflows'),
13
+ distRoot: paths.root('workflows'),
14
+ artifactDisk: 'local',
15
+ production: env.NODE_ENV === 'production',
16
+ },
17
+ {
18
+ rootDir: paths.root(),
19
+ serverDir: paths.server(),
20
+ },
21
+ ),
22
+ );
23
+
24
+ export default workflow;
@@ -0,0 +1,24 @@
1
+ import {
2
+ AppConfig,
3
+ resolveDefaultAppConfigFile,
4
+ } from '@nocobase/app-server/config';
5
+ import type { ResolvedAppRuntimeConfigContext } from '@nocobase/app-server/runtime';
6
+
7
+ export function createAppConfig(
8
+ context: ResolvedAppRuntimeConfigContext,
9
+ ): AppConfig {
10
+ const config = new AppConfig();
11
+ const configuredPath =
12
+ context.configPath ?? context.environment.APP_CONFIG_FILE;
13
+ // Deployment configuration stays beside the compiled code directory.
14
+ const configPath =
15
+ configuredPath === undefined
16
+ ? resolveDefaultAppConfigFile(context.paths)
17
+ : context.paths.root(configuredPath);
18
+
19
+ // Environment variables are declared by the sections they set, in `env` of each `defineAppConfig`, and loaded
20
+ // above this file once the sections are known. `pnpm nocobase config env` lists them.
21
+ config.loadFile(configPath, { optional: configuredPath === undefined });
22
+
23
+ return config;
24
+ }
@@ -0,0 +1,23 @@
1
+ import type { Application } from '@nocobase/app-server/application';
2
+ import {
3
+ resolveAppRuntime,
4
+ startApplicationInScope,
5
+ type AppDisposer,
6
+ type AppScope,
7
+ } from '@nocobase/app-server/runtime';
8
+
9
+ import { createApp } from './app.js';
10
+ import appRuntime from './runtime.js';
11
+
12
+ export type { AppDisposer, AppScope };
13
+
14
+ export type EmbeddedServer = Application;
15
+
16
+ export async function createServer(scope: AppScope): Promise<EmbeddedServer> {
17
+ const runtime = await resolveAppRuntime(appRuntime, scope);
18
+ const app = createApp(runtime);
19
+
20
+ return startApplicationInScope(scope, app);
21
+ }
22
+
23
+ export default createServer;
@@ -0,0 +1,10 @@
1
+ import type { LocaleResource } from '@nocobase/i18n';
2
+
3
+ // The application's own server-side wording. It is empty because every string the server produces today belongs to a
4
+ // plugin's namespace; add keys here as the application starts producing its own, and use `overrides` to reword a
5
+ // plugin's.
6
+ const enUS = {};
7
+
8
+ export type AppServerResource = LocaleResource<typeof enUS>;
9
+
10
+ export default enUS;