create-flowdular 0.2.6 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-template/.agents/skills/agent-tool-design/SKILL.md +1 -1
- package/agent-template/.agents/skills/auth-security-review/SKILL.md +1 -1
- package/agent-template/.agents/skills/cli-extension/SKILL.md +1 -1
- package/agent-template/.agents/skills/deploy-operate/SKILL.md +114 -0
- package/agent-template/.agents/skills/module-new/SKILL.md +29 -0
- package/agent-template/.agents/skills/module-update/SKILL.md +9 -1
- package/agent-template/.agents/skills/spec-interview/SKILL.md +114 -0
- package/agent-template/.agents/skills/ux-design/SKILL.md +34 -3
- package/agent-template/.ai/README.md +2 -1
- package/agent-template/.ai/agents/sandbox/business-manager.md +5 -1
- package/agent-template/.ai/blueprints/author-spec/README.md +1 -1
- package/agent-template/.ai/blueprints/author-spec/spec-requirements.yaml +44 -0
- package/agent-template/.ai/blueprints/author-spec/steps.yaml +5 -5
- package/agent-template/.ai/blueprints/author-spec/templates/module.yaml +99 -3
- package/agent-template/.ai/blueprints/edit-module/gates.yaml +4 -0
- package/agent-template/.ai/blueprints/edit-module/required-files.yaml +9 -0
- package/agent-template/.ai/blueprints/new-module/gates.yaml +4 -0
- package/agent-template/.ai/blueprints/new-module/spec-requirements.yaml +2 -2
- package/agent-template/.ai/blueprints/release/gates.yaml +4 -0
- package/agent-template/.ai/platform-capabilities.md +128 -0
- package/agent-template/.ai/policies/capabilities.yaml +130 -3
- package/agent-template/.ai/policies/path-ownership.yaml +5 -2
- package/agent-template/.ai/policies/task-budgets.yaml +5 -3
- package/agent-template/.ai/references/catalog/module.json +4 -4
- package/agent-template/.ai/references/catalog/package.json +2 -2
- package/agent-template/.ai/references/catalog/spec/module.yaml +5 -3
- package/agent-template/.ai/references/catalog/src/platform.ts +2 -0
- package/agent-template/.ai/references/catalog/src/services/catalog-service.ts +89 -1
- package/agent-template/.ai/references/catalog/src/services/data-classes.ts +47 -0
- package/agent-template/.ai/references/catalog/src/services/database-repository.ts +98 -1
- package/agent-template/.ai/references/catalog/src/services/repository.ts +22 -1
- package/agent-template/.ai/references/catalog/tests/data-classes.test.ts +157 -0
- package/agent-template/.ai/references/catalog.provenance.json +12 -10
- package/agent-template/.ai/rules/flowdular.md +4 -0
- package/agent-template/.ai/skills/README.md +10 -0
- package/agent-template/.ai/skills/agent-tool-design/SKILL.md +1 -2
- package/agent-template/.ai/skills/auth-security-review/SKILL.md +1 -1
- package/agent-template/.ai/skills/business-agent-design/SKILL.md +0 -1
- package/agent-template/.ai/skills/cli-extension/SKILL.md +1 -1
- package/agent-template/.ai/skills/deploy-operate/SKILL.md +119 -0
- package/agent-template/.ai/skills/module-new/SKILL.md +29 -3
- package/agent-template/.ai/skills/module-update/SKILL.md +9 -3
- package/agent-template/.ai/skills/perf-audit/SKILL.md +0 -1
- package/agent-template/.ai/skills/release-eject-pr/SKILL.md +0 -1
- package/agent-template/.ai/skills/spec-interview/SKILL.md +120 -0
- package/agent-template/.ai/skills/test-hardening/SKILL.md +1 -0
- package/agent-template/.ai/skills/ux-design/SKILL.md +34 -3
- package/agent-template/.ai/skills/variables/SKILL.md +0 -2
- package/agent-template/.ai/skills/workflow-development/SKILL.md +0 -1
- package/agent-template/.claude/skills/agent-tool-design/SKILL.md +1 -1
- package/agent-template/.claude/skills/auth-security-review/SKILL.md +1 -1
- package/agent-template/.claude/skills/cli-extension/SKILL.md +1 -1
- package/agent-template/.claude/skills/deploy-operate/SKILL.md +114 -0
- package/agent-template/.claude/skills/module-new/SKILL.md +29 -0
- package/agent-template/.claude/skills/module-update/SKILL.md +9 -1
- package/agent-template/.claude/skills/spec-interview/SKILL.md +114 -0
- package/agent-template/.claude/skills/ux-design/SKILL.md +34 -3
- package/agent-template/AGENTS.md +4 -0
- package/agent-template/CLAUDE.md +4 -0
- package/agent-template/docs/adr/0003-module-settings.md +1 -1
- package/agent-template/docs/adr/0006-agentic-workflows.md +24 -21
- package/agent-template/docs/agent-contract.md +2 -2
- package/agent-template/docs/cli-extensions.md +82 -0
- package/agent-template/docs/cli.md +195 -0
- package/agent-template/docs/configuration.md +593 -36
- package/agent-template/docs/design-system.md +185 -31
- package/agent-template/docs/getting-started.md +118 -0
- package/agent-template/docs/module-distribution.md +96 -0
- package/agent-template/docs/module-web-surfaces.md +221 -0
- package/agent-template/docs/modules.md +216 -0
- package/agent-template/docs/operations.md +545 -0
- package/agent-template/docs/sandbox.md +212 -0
- package/agent-template/platform/scripts/build.mjs +11 -0
- package/dist/bin.js +29 -0
- package/package.json +1 -1
- package/template/default/.dockerignore +14 -0
- package/template/default/.env.example +96 -0
- package/template/default/README.md +37 -1
- package/template/default/flowdular.json +15 -4
- package/template/default/infra/README.md +116 -0
- package/template/default/infra/docker/Dockerfile +37 -0
- package/template/default/infra/docker/compose.yaml +158 -0
- package/template/default/infra/docker/postgres/10-roles.sh +31 -0
- package/template/default/infra/docker/postgres/tls-init.sh +28 -0
- package/template/default/infra/kubernetes/database-secret.example.yaml +15 -0
- package/template/default/infra/kubernetes/deployment.yaml +211 -0
- package/template/default/infra/kubernetes/kustomization.yaml +9 -0
- package/template/default/infra/kubernetes/secrets.example.yaml +52 -0
- package/template/default/infra/kubernetes/service.yaml +13 -0
- package/template/default/modules/example/module.json +2 -1
- package/template/default/modules/example/package.json +1 -1
- package/template/default/modules/example/spec/module.yaml +1 -1
- package/template/default/modules/example/src/services/database-repository.ts +2 -12
- package/template/default/package.json +3 -2
- package/template/default/platform/octane.config.ts +99 -9
- package/template/default/platform/package.json +1 -1
- package/template/default/platform/src/generated/modules.client.ts +26 -2
- package/template/default/platform/src/generated/modules.server.ts +241 -10
- package/template/default/platform/src/server/health.ts +47 -0
- package/template/default/platform/src/server/metrics.ts +100 -0
- package/template/default/platform/src/server/storage.ts +172 -0
- package/template/default/platform/src/server/tracing.ts +85 -0
- package/template/default/specs/application.yaml +15 -0
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import {
|
|
2
2
|
assertRouteConflicts,
|
|
3
|
+
createModuleMetrics,
|
|
3
4
|
createModuleWebRoutes,
|
|
4
5
|
createApplicationRoutes,
|
|
6
|
+
serverTracer,
|
|
5
7
|
validateApplicationPath,
|
|
8
|
+
createMailPort,
|
|
9
|
+
mailConfigFromEnvironment,
|
|
6
10
|
} from '@flowdular/sdk/server';
|
|
11
|
+
import {
|
|
12
|
+
createDataClassRegistry,
|
|
13
|
+
PLATFORM_SETTINGS_TENANT,
|
|
14
|
+
} from '@flowdular/sdk/kernel';
|
|
7
15
|
import { resolve } from 'node:path';
|
|
8
16
|
import { defineConfig, RenderRoute } from '@octanejs/vite-plugin';
|
|
9
17
|
import {
|
|
10
18
|
authRuntimeOptionsFromEnvironment,
|
|
11
19
|
createAuthRoutes,
|
|
20
|
+
isTokenPrincipal,
|
|
21
|
+
mfaEnrolmentSatisfied,
|
|
12
22
|
principalFromContext,
|
|
13
23
|
createAuthRuntime,
|
|
14
24
|
createPlatformAgentRegistry,
|
|
15
25
|
createPlatformCapabilityRegistry,
|
|
16
26
|
createPlatformToolRegistry,
|
|
27
|
+
nodemailerSmtpTransport,
|
|
17
28
|
} from '@flowdular/sdk/modules/auth/server';
|
|
18
29
|
import {
|
|
19
30
|
composeModuleServer,
|
|
@@ -24,6 +35,18 @@ import {
|
|
|
24
35
|
createPlatformDatabaseProvider,
|
|
25
36
|
databaseProviderConfigFromEnvironment,
|
|
26
37
|
} from './src/server/database.ts';
|
|
38
|
+
import {
|
|
39
|
+
createReadinessEndpoint,
|
|
40
|
+
healthEndpoint,
|
|
41
|
+
} from './src/server/health.ts';
|
|
42
|
+
import { createMetricsRoutes } from './src/server/metrics.ts';
|
|
43
|
+
import { createPlatformObservability } from './src/server/tracing.ts';
|
|
44
|
+
import {
|
|
45
|
+
createStorageKeyring,
|
|
46
|
+
createStoragePort,
|
|
47
|
+
createStorageRoutes,
|
|
48
|
+
storageConfigFromEnvironment,
|
|
49
|
+
} from './src/server/storage.ts';
|
|
27
50
|
|
|
28
51
|
function checkedRoutes<T extends Parameters<typeof assertRouteConflicts>[0]>(
|
|
29
52
|
routes: T,
|
|
@@ -36,19 +59,53 @@ const SHELL = ['App', '/src/App.tsrx'] as const;
|
|
|
36
59
|
const workspaceRoot = resolve(import.meta.dirname, '..');
|
|
37
60
|
const building = process.env.FD_INTERNAL_BUILD === 'true';
|
|
38
61
|
|
|
62
|
+
/* Composed first and drained last: a trace or an error report is evidence about
|
|
63
|
+
the boot that follows it, and both egresses refuse a misconfigured endpoint
|
|
64
|
+
here rather than at the first request that needed them. */
|
|
65
|
+
const observability = createPlatformObservability({
|
|
66
|
+
environment: building
|
|
67
|
+
? { ...process.env, NODE_ENV: 'development' }
|
|
68
|
+
: process.env,
|
|
69
|
+
});
|
|
39
70
|
const databases = createPlatformDatabaseProvider(
|
|
40
71
|
databaseProviderConfigFromEnvironment(
|
|
41
72
|
building ? { ...process.env, NODE_ENV: 'development' } : process.env,
|
|
42
73
|
workspaceRoot,
|
|
43
74
|
),
|
|
44
75
|
);
|
|
76
|
+
const storageKeyring = createStorageKeyring(process.env, workspaceRoot);
|
|
77
|
+
const storage = createStoragePort(
|
|
78
|
+
storageConfigFromEnvironment(
|
|
79
|
+
building ? { ...process.env, NODE_ENV: 'development' } : process.env,
|
|
80
|
+
workspaceRoot,
|
|
81
|
+
),
|
|
82
|
+
{ keyring: storageKeyring },
|
|
83
|
+
);
|
|
45
84
|
const configuredApplicationPath = validateApplicationPath(
|
|
46
85
|
process.env.FD_APPLICATION_PATH ?? applicationBasePath,
|
|
47
86
|
);
|
|
87
|
+
/* One outbound transport for the whole deployment. auth.core is only its
|
|
88
|
+
first sender; the SMTP client comes from that module because it is the one
|
|
89
|
+
that declares the dependency. */
|
|
90
|
+
const mail = createMailPort(
|
|
91
|
+
mailConfigFromEnvironment(
|
|
92
|
+
building ? { ...process.env, NODE_ENV: 'development' } : process.env,
|
|
93
|
+
),
|
|
94
|
+
{ createSmtpTransport: nodemailerSmtpTransport },
|
|
95
|
+
);
|
|
96
|
+
/* Created before the auth runtime so auth.core, which composes outside the
|
|
97
|
+
generated module list, declares its data classes into the same registry. */
|
|
98
|
+
const dataClasses = createDataClassRegistry();
|
|
48
99
|
const authRuntime = createAuthRuntime({
|
|
49
|
-
...authRuntimeOptionsFromEnvironment(
|
|
100
|
+
...authRuntimeOptionsFromEnvironment(
|
|
101
|
+
building ? { ...process.env, NODE_ENV: 'development' } : process.env,
|
|
102
|
+
workspaceRoot,
|
|
103
|
+
),
|
|
50
104
|
applicationPath: configuredApplicationPath,
|
|
51
105
|
databases,
|
|
106
|
+
dataClasses,
|
|
107
|
+
mail,
|
|
108
|
+
metrics: createModuleMetrics('auth.core'),
|
|
52
109
|
});
|
|
53
110
|
|
|
54
111
|
/* Module APIs come from the generated composition. Enable or disable modules
|
|
@@ -63,17 +120,30 @@ const moduleCompositions = composeModuleServer({
|
|
|
63
120
|
agentTools: createPlatformToolRegistry(),
|
|
64
121
|
agentDefinitions,
|
|
65
122
|
capabilities: createPlatformCapabilityRegistry(),
|
|
123
|
+
dataClasses,
|
|
66
124
|
databases,
|
|
125
|
+
storage,
|
|
126
|
+
mail,
|
|
127
|
+
/* Rebound to the composing module by the generated composition; this binding
|
|
128
|
+
is what a series the platform itself records would carry. */
|
|
129
|
+
metrics: createModuleMetrics('platform'),
|
|
130
|
+
tracer: serverTracer(),
|
|
67
131
|
});
|
|
68
132
|
for (const composition of moduleCompositions) {
|
|
69
133
|
if (composition.settings) settings.declare(composition.settings);
|
|
70
134
|
}
|
|
71
135
|
agentDefinitions.seal();
|
|
136
|
+
/* Sealed once every composition has run and before any start hook reads the
|
|
137
|
+
catalogue, so every reader sees the declarations the modules agreed on. */
|
|
138
|
+
dataClasses.seal();
|
|
72
139
|
|
|
73
140
|
/* check() proves the runtime role holds neither SUPERUSER nor BYPASSRLS before
|
|
74
141
|
any module reads a row. */
|
|
75
142
|
if (!building) {
|
|
76
143
|
await databases.check();
|
|
144
|
+
/* Platform-scoped settings are read by background work before any request
|
|
145
|
+
could prime them; a workspace is primed by the authentication middleware. */
|
|
146
|
+
await settings.prime(PLATFORM_SETTINGS_TENANT);
|
|
77
147
|
for (const composition of moduleCompositions) await composition.prepare?.();
|
|
78
148
|
for (const composition of moduleCompositions) composition.start?.();
|
|
79
149
|
}
|
|
@@ -87,7 +157,11 @@ const shutdown = async () => {
|
|
|
87
157
|
await composition.dispose?.();
|
|
88
158
|
}
|
|
89
159
|
await authRuntime.dispose();
|
|
160
|
+
await storage.dispose();
|
|
90
161
|
await databases.dispose();
|
|
162
|
+
/* Last, so the spans and error reports this process queued while it stopped
|
|
163
|
+
still leave with it. */
|
|
164
|
+
await observability.dispose();
|
|
91
165
|
};
|
|
92
166
|
// Bundling needs route declarations without background work or retained leases.
|
|
93
167
|
if (building) {
|
|
@@ -106,21 +180,37 @@ export default defineConfig({
|
|
|
106
180
|
entry: SHELL,
|
|
107
181
|
publicRoot: moduleWebMounts.some((site) => site.path === '/'),
|
|
108
182
|
}),
|
|
183
|
+
healthEndpoint.serverRoute,
|
|
184
|
+
createReadinessEndpoint(databases).serverRoute,
|
|
185
|
+
...createMetricsRoutes({ environment: process.env }),
|
|
186
|
+
...createStorageRoutes({
|
|
187
|
+
storage,
|
|
188
|
+
keyring: storageKeyring,
|
|
189
|
+
environment: process.env,
|
|
190
|
+
}),
|
|
109
191
|
...createAuthRoutes(authRuntime),
|
|
110
192
|
...moduleCompositions.flatMap((composition) => composition.routes),
|
|
111
193
|
...createModuleWebRoutes({
|
|
112
194
|
modules: moduleCompositions,
|
|
113
195
|
mounts: moduleWebMounts,
|
|
114
196
|
applicationPath: configuredApplicationPath,
|
|
115
|
-
resolveIdentity: (context) => {
|
|
197
|
+
resolveIdentity: async (context) => {
|
|
116
198
|
const principal = principalFromContext(context);
|
|
117
|
-
return
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
199
|
+
if (!principal) return null;
|
|
200
|
+
/* The /api gate does not reach these pages, and a member who
|
|
201
|
+
still owes enrolment must not read workspace data from one.
|
|
202
|
+
Machine credentials cannot enrol and stay exempt there too. */
|
|
203
|
+
if (
|
|
204
|
+
!isTokenPrincipal(context) &&
|
|
205
|
+
!(await mfaEnrolmentSatisfied(authRuntime, principal))
|
|
206
|
+
) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
subjectId: principal.accountId,
|
|
211
|
+
tenantId: principal.tenantId,
|
|
212
|
+
permissions: new Set(principal.scopes),
|
|
213
|
+
};
|
|
124
214
|
},
|
|
125
215
|
}),
|
|
126
216
|
]),
|
|
@@ -7,12 +7,24 @@ import type {
|
|
|
7
7
|
} from '@flowdular/sdk/client';
|
|
8
8
|
import { createClientContribution as system_core } from '@flowdular/sdk/modules/system/client';
|
|
9
9
|
import { createClientContribution as auth_core } from '@flowdular/sdk/modules/auth/client';
|
|
10
|
+
import { createClientContribution as access_core } from '@flowdular/sdk/modules/access/client';
|
|
11
|
+
import { createClientContribution as reports_core } from '@flowdular/sdk/modules/reports/client';
|
|
12
|
+
import { createClientContribution as metering_core } from '@flowdular/sdk/modules/metering/client';
|
|
10
13
|
import { createClientContribution as agents_core } from '@flowdular/sdk/modules/agents/client';
|
|
11
|
-
import { createClientContribution as
|
|
14
|
+
import { createClientContribution as approvals_core } from '@flowdular/sdk/modules/approvals/client';
|
|
15
|
+
import { createClientContribution as audit_core } from '@flowdular/sdk/modules/audit/client';
|
|
12
16
|
import { createClientContribution as workflows_core } from '@flowdular/sdk/modules/workflows/client';
|
|
17
|
+
import { createClientContribution as automations_core } from '@flowdular/sdk/modules/automations/client';
|
|
18
|
+
import { createClientContribution as connectors_core } from '@flowdular/sdk/modules/connectors/client';
|
|
19
|
+
import { createClientContribution as directory_core } from '@flowdular/sdk/modules/directory/client';
|
|
20
|
+
import { createClientContribution as documents_core } from '@flowdular/sdk/modules/documents/client';
|
|
13
21
|
import { createClientContribution as example_core } from '@app/module-example/client';
|
|
22
|
+
import { createClientContribution as exports_core } from '@flowdular/sdk/modules/exports/client';
|
|
23
|
+
import { createClientContribution as import_core } from '@flowdular/sdk/modules/import/client';
|
|
24
|
+
import { createClientContribution as notifications_core } from '@flowdular/sdk/modules/notifications/client';
|
|
14
25
|
import { createClientContribution as profile_core } from '@flowdular/sdk/modules/profile/client';
|
|
15
26
|
import { createClientContribution as sandbox_core } from '@flowdular/sdk/modules/sandbox/client';
|
|
27
|
+
import { createClientContribution as search_core } from '@flowdular/sdk/modules/search/client';
|
|
16
28
|
import { createClientContribution as users_core } from '@flowdular/sdk/modules/users/client';
|
|
17
29
|
|
|
18
30
|
export function createModuleClientContributions(
|
|
@@ -21,12 +33,24 @@ export function createModuleClientContributions(
|
|
|
21
33
|
return [
|
|
22
34
|
system_core(context),
|
|
23
35
|
auth_core(context),
|
|
36
|
+
access_core(context),
|
|
37
|
+
reports_core(context),
|
|
38
|
+
metering_core(context),
|
|
24
39
|
agents_core(context),
|
|
25
|
-
|
|
40
|
+
approvals_core(context),
|
|
41
|
+
audit_core(context),
|
|
26
42
|
workflows_core(context),
|
|
43
|
+
automations_core(context),
|
|
44
|
+
connectors_core(context),
|
|
45
|
+
directory_core(context),
|
|
46
|
+
documents_core(context),
|
|
27
47
|
example_core(context),
|
|
48
|
+
exports_core(context),
|
|
49
|
+
import_core(context),
|
|
50
|
+
notifications_core(context),
|
|
28
51
|
profile_core(context),
|
|
29
52
|
sandbox_core(context),
|
|
53
|
+
search_core(context),
|
|
30
54
|
users_core(context),
|
|
31
55
|
];
|
|
32
56
|
}
|
|
@@ -5,14 +5,26 @@ import type {
|
|
|
5
5
|
PlatformServerContext,
|
|
6
6
|
} from '@flowdular/sdk/modules/auth/server';
|
|
7
7
|
import type { WebMount } from '@flowdular/sdk/server';
|
|
8
|
+
import { createModuleMetrics } from '@flowdular/sdk/server';
|
|
8
9
|
import { createServerComposition as system_core } from '@flowdular/sdk/modules/system/platform';
|
|
10
|
+
import { createServerComposition as access_core } from '@flowdular/sdk/modules/access/platform';
|
|
11
|
+
import { createServerComposition as reports_core } from '@flowdular/sdk/modules/reports/platform';
|
|
12
|
+
import { createServerComposition as metering_core } from '@flowdular/sdk/modules/metering/platform';
|
|
9
13
|
import { createServerComposition as agents_core } from '@flowdular/sdk/modules/agents/platform';
|
|
10
|
-
import { createServerComposition as
|
|
14
|
+
import { createServerComposition as approvals_core } from '@flowdular/sdk/modules/approvals/platform';
|
|
15
|
+
import { createServerComposition as audit_core } from '@flowdular/sdk/modules/audit/platform';
|
|
11
16
|
import { createServerComposition as workflows_core } from '@flowdular/sdk/modules/workflows/platform';
|
|
12
|
-
import { createServerComposition as
|
|
17
|
+
import { createServerComposition as automations_core } from '@flowdular/sdk/modules/automations/platform';
|
|
18
|
+
import { createServerComposition as connectors_core } from '@flowdular/sdk/modules/connectors/platform';
|
|
19
|
+
import { createServerComposition as directory_core } from '@flowdular/sdk/modules/directory/platform';
|
|
20
|
+
import { createServerComposition as documents_core } from '@flowdular/sdk/modules/documents/platform';
|
|
13
21
|
import { createServerComposition as example_core } from '@app/module-example/platform';
|
|
22
|
+
import { createServerComposition as exports_core } from '@flowdular/sdk/modules/exports/platform';
|
|
23
|
+
import { createServerComposition as import_core } from '@flowdular/sdk/modules/import/platform';
|
|
24
|
+
import { createServerComposition as notifications_core } from '@flowdular/sdk/modules/notifications/platform';
|
|
14
25
|
import { createServerComposition as profile_core } from '@flowdular/sdk/modules/profile/platform';
|
|
15
26
|
import { createServerComposition as sandbox_core } from '@flowdular/sdk/modules/sandbox/platform';
|
|
27
|
+
import { createServerComposition as search_core } from '@flowdular/sdk/modules/search/platform';
|
|
16
28
|
import { createServerComposition as users_core } from '@flowdular/sdk/modules/users/platform';
|
|
17
29
|
|
|
18
30
|
export function composeModuleServer(
|
|
@@ -23,51 +35,241 @@ export function composeModuleServer(
|
|
|
23
35
|
...system_core({
|
|
24
36
|
...context,
|
|
25
37
|
agentDefinitions: context.agentDefinitions.forModule('system.core'),
|
|
38
|
+
dataClasses: context.dataClasses.forModule('system.core'),
|
|
39
|
+
capabilities: context.capabilities.forModule('system.core', {
|
|
40
|
+
provides: [],
|
|
41
|
+
requires: [],
|
|
42
|
+
}),
|
|
43
|
+
metrics: createModuleMetrics('system.core'),
|
|
26
44
|
}),
|
|
27
45
|
moduleId: 'system.core',
|
|
28
46
|
},
|
|
47
|
+
{
|
|
48
|
+
...access_core({
|
|
49
|
+
...context,
|
|
50
|
+
agentDefinitions: context.agentDefinitions.forModule('access.core'),
|
|
51
|
+
dataClasses: context.dataClasses.forModule('access.core'),
|
|
52
|
+
capabilities: context.capabilities.forModule('access.core', {
|
|
53
|
+
provides: [],
|
|
54
|
+
requires: [{ id: 'exports.lists.v1', optional: true }],
|
|
55
|
+
}),
|
|
56
|
+
metrics: createModuleMetrics('access.core'),
|
|
57
|
+
}),
|
|
58
|
+
moduleId: 'access.core',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
...reports_core({
|
|
62
|
+
...context,
|
|
63
|
+
agentDefinitions: context.agentDefinitions.forModule('reports.core'),
|
|
64
|
+
dataClasses: context.dataClasses.forModule('reports.core'),
|
|
65
|
+
capabilities: context.capabilities.forModule('reports.core', {
|
|
66
|
+
provides: ['reports.v1'],
|
|
67
|
+
requires: [],
|
|
68
|
+
}),
|
|
69
|
+
metrics: createModuleMetrics('reports.core'),
|
|
70
|
+
}),
|
|
71
|
+
moduleId: 'reports.core',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
...metering_core({
|
|
75
|
+
...context,
|
|
76
|
+
agentDefinitions: context.agentDefinitions.forModule('metering.core'),
|
|
77
|
+
dataClasses: context.dataClasses.forModule('metering.core'),
|
|
78
|
+
capabilities: context.capabilities.forModule('metering.core', {
|
|
79
|
+
provides: ['metering.meters.v1'],
|
|
80
|
+
requires: [
|
|
81
|
+
{ id: 'notifications.publish.v1', optional: true },
|
|
82
|
+
{ id: 'reports.v1', optional: true },
|
|
83
|
+
],
|
|
84
|
+
}),
|
|
85
|
+
metrics: createModuleMetrics('metering.core'),
|
|
86
|
+
}),
|
|
87
|
+
moduleId: 'metering.core',
|
|
88
|
+
},
|
|
29
89
|
{
|
|
30
90
|
...agents_core({
|
|
31
91
|
...context,
|
|
32
92
|
agentDefinitions: context.agentDefinitions.forModule('agents.core'),
|
|
93
|
+
dataClasses: context.dataClasses.forModule('agents.core'),
|
|
94
|
+
capabilities: context.capabilities.forModule('agents.core', {
|
|
95
|
+
provides: [
|
|
96
|
+
'agents.run-queue',
|
|
97
|
+
'agents.run-execution.v2',
|
|
98
|
+
'agents.actions.v1',
|
|
99
|
+
],
|
|
100
|
+
requires: [
|
|
101
|
+
{ id: 'notifications.publish.v1', optional: true },
|
|
102
|
+
{ id: 'metering.meters.v1' },
|
|
103
|
+
{ id: 'reports.v1', optional: true },
|
|
104
|
+
],
|
|
105
|
+
}),
|
|
106
|
+
metrics: createModuleMetrics('agents.core'),
|
|
33
107
|
}),
|
|
34
108
|
moduleId: 'agents.core',
|
|
35
109
|
},
|
|
110
|
+
{
|
|
111
|
+
...approvals_core({
|
|
112
|
+
...context,
|
|
113
|
+
agentDefinitions: context.agentDefinitions.forModule('approvals.core'),
|
|
114
|
+
dataClasses: context.dataClasses.forModule('approvals.core'),
|
|
115
|
+
capabilities: context.capabilities.forModule('approvals.core', {
|
|
116
|
+
provides: ['approvals.requests.v1'],
|
|
117
|
+
requires: [{ id: 'notifications.publish.v1', optional: true }],
|
|
118
|
+
}),
|
|
119
|
+
metrics: createModuleMetrics('approvals.core'),
|
|
120
|
+
}),
|
|
121
|
+
moduleId: 'approvals.core',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
...audit_core({
|
|
125
|
+
...context,
|
|
126
|
+
agentDefinitions: context.agentDefinitions.forModule('audit.core'),
|
|
127
|
+
dataClasses: context.dataClasses.forModule('audit.core'),
|
|
128
|
+
capabilities: context.capabilities.forModule('audit.core', {
|
|
129
|
+
provides: ['audit.erasure.v1'],
|
|
130
|
+
requires: [],
|
|
131
|
+
}),
|
|
132
|
+
metrics: createModuleMetrics('audit.core'),
|
|
133
|
+
}),
|
|
134
|
+
moduleId: 'audit.core',
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
...workflows_core({
|
|
138
|
+
...context,
|
|
139
|
+
agentDefinitions: context.agentDefinitions.forModule('workflows.core'),
|
|
140
|
+
dataClasses: context.dataClasses.forModule('workflows.core'),
|
|
141
|
+
capabilities: context.capabilities.forModule('workflows.core', {
|
|
142
|
+
provides: ['workflows.execution.v1'],
|
|
143
|
+
requires: [
|
|
144
|
+
{ id: 'agents.run-execution.v2' },
|
|
145
|
+
{ id: 'agents.actions.v1' },
|
|
146
|
+
{ id: 'notifications.publish.v1', optional: true },
|
|
147
|
+
{ id: 'approvals.requests.v1', optional: true },
|
|
148
|
+
],
|
|
149
|
+
}),
|
|
150
|
+
metrics: createModuleMetrics('workflows.core'),
|
|
151
|
+
}),
|
|
152
|
+
moduleId: 'workflows.core',
|
|
153
|
+
},
|
|
36
154
|
{
|
|
37
155
|
...automations_core({
|
|
38
156
|
...context,
|
|
39
157
|
agentDefinitions:
|
|
40
158
|
context.agentDefinitions.forModule('automations.core'),
|
|
159
|
+
dataClasses: context.dataClasses.forModule('automations.core'),
|
|
160
|
+
capabilities: context.capabilities.forModule('automations.core', {
|
|
161
|
+
provides: ['automations.targets.v1', 'automations.execution.v1'],
|
|
162
|
+
requires: [
|
|
163
|
+
{ id: 'agents.run-queue' },
|
|
164
|
+
{ id: 'workflows.execution.v1', optional: true },
|
|
165
|
+
],
|
|
166
|
+
}),
|
|
167
|
+
metrics: createModuleMetrics('automations.core'),
|
|
41
168
|
}),
|
|
42
169
|
moduleId: 'automations.core',
|
|
43
170
|
},
|
|
44
171
|
{
|
|
45
|
-
...
|
|
172
|
+
...connectors_core({
|
|
46
173
|
...context,
|
|
47
|
-
agentDefinitions: context.agentDefinitions.forModule('
|
|
174
|
+
agentDefinitions: context.agentDefinitions.forModule('connectors.core'),
|
|
175
|
+
dataClasses: context.dataClasses.forModule('connectors.core'),
|
|
176
|
+
capabilities: context.capabilities.forModule('connectors.core', {
|
|
177
|
+
provides: ['connectors.definitions.v1', 'connectors.calls.v1'],
|
|
178
|
+
requires: [],
|
|
179
|
+
}),
|
|
180
|
+
metrics: createModuleMetrics('connectors.core'),
|
|
48
181
|
}),
|
|
49
|
-
moduleId: '
|
|
182
|
+
moduleId: 'connectors.core',
|
|
50
183
|
},
|
|
51
184
|
{
|
|
52
|
-
...
|
|
185
|
+
...directory_core({
|
|
53
186
|
...context,
|
|
54
|
-
agentDefinitions: context.agentDefinitions.forModule(
|
|
55
|
-
|
|
56
|
-
|
|
187
|
+
agentDefinitions: context.agentDefinitions.forModule('directory.core'),
|
|
188
|
+
dataClasses: context.dataClasses.forModule('directory.core'),
|
|
189
|
+
capabilities: context.capabilities.forModule('directory.core', {
|
|
190
|
+
provides: [],
|
|
191
|
+
requires: [],
|
|
192
|
+
}),
|
|
193
|
+
metrics: createModuleMetrics('directory.core'),
|
|
57
194
|
}),
|
|
58
|
-
moduleId: '
|
|
195
|
+
moduleId: 'directory.core',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
...documents_core({
|
|
199
|
+
...context,
|
|
200
|
+
agentDefinitions: context.agentDefinitions.forModule('documents.core'),
|
|
201
|
+
dataClasses: context.dataClasses.forModule('documents.core'),
|
|
202
|
+
capabilities: context.capabilities.forModule('documents.core', {
|
|
203
|
+
provides: ['documents.attachments.v1'],
|
|
204
|
+
requires: [],
|
|
205
|
+
}),
|
|
206
|
+
metrics: createModuleMetrics('documents.core'),
|
|
207
|
+
}),
|
|
208
|
+
moduleId: 'documents.core',
|
|
59
209
|
},
|
|
60
210
|
{
|
|
61
211
|
...example_core({
|
|
62
212
|
...context,
|
|
63
213
|
agentDefinitions: context.agentDefinitions.forModule('example.core'),
|
|
214
|
+
dataClasses: context.dataClasses.forModule('example.core'),
|
|
215
|
+
capabilities: context.capabilities.forModule('example.core', {
|
|
216
|
+
provides: [],
|
|
217
|
+
requires: [],
|
|
218
|
+
}),
|
|
219
|
+
metrics: createModuleMetrics('example.core'),
|
|
64
220
|
}),
|
|
65
221
|
moduleId: 'example.core',
|
|
66
222
|
},
|
|
223
|
+
{
|
|
224
|
+
...exports_core({
|
|
225
|
+
...context,
|
|
226
|
+
agentDefinitions: context.agentDefinitions.forModule('exports.core'),
|
|
227
|
+
dataClasses: context.dataClasses.forModule('exports.core'),
|
|
228
|
+
capabilities: context.capabilities.forModule('exports.core', {
|
|
229
|
+
provides: ['exports.lists.v1'],
|
|
230
|
+
requires: [],
|
|
231
|
+
}),
|
|
232
|
+
metrics: createModuleMetrics('exports.core'),
|
|
233
|
+
}),
|
|
234
|
+
moduleId: 'exports.core',
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
...import_core({
|
|
238
|
+
...context,
|
|
239
|
+
agentDefinitions: context.agentDefinitions.forModule('import.core'),
|
|
240
|
+
dataClasses: context.dataClasses.forModule('import.core'),
|
|
241
|
+
capabilities: context.capabilities.forModule('import.core', {
|
|
242
|
+
provides: ['import.ports.v1'],
|
|
243
|
+
requires: [{ id: 'documents.attachments.v1' }],
|
|
244
|
+
}),
|
|
245
|
+
metrics: createModuleMetrics('import.core'),
|
|
246
|
+
}),
|
|
247
|
+
moduleId: 'import.core',
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
...notifications_core({
|
|
251
|
+
...context,
|
|
252
|
+
agentDefinitions:
|
|
253
|
+
context.agentDefinitions.forModule('notifications.core'),
|
|
254
|
+
dataClasses: context.dataClasses.forModule('notifications.core'),
|
|
255
|
+
capabilities: context.capabilities.forModule('notifications.core', {
|
|
256
|
+
provides: ['notifications.publish.v1'],
|
|
257
|
+
requires: [],
|
|
258
|
+
}),
|
|
259
|
+
metrics: createModuleMetrics('notifications.core'),
|
|
260
|
+
}),
|
|
261
|
+
moduleId: 'notifications.core',
|
|
262
|
+
},
|
|
67
263
|
{
|
|
68
264
|
...profile_core({
|
|
69
265
|
...context,
|
|
70
266
|
agentDefinitions: context.agentDefinitions.forModule('profile.core'),
|
|
267
|
+
dataClasses: context.dataClasses.forModule('profile.core'),
|
|
268
|
+
capabilities: context.capabilities.forModule('profile.core', {
|
|
269
|
+
provides: [],
|
|
270
|
+
requires: [],
|
|
271
|
+
}),
|
|
272
|
+
metrics: createModuleMetrics('profile.core'),
|
|
71
273
|
}),
|
|
72
274
|
moduleId: 'profile.core',
|
|
73
275
|
},
|
|
@@ -75,13 +277,42 @@ export function composeModuleServer(
|
|
|
75
277
|
...sandbox_core({
|
|
76
278
|
...context,
|
|
77
279
|
agentDefinitions: context.agentDefinitions.forModule('sandbox.core'),
|
|
280
|
+
dataClasses: context.dataClasses.forModule('sandbox.core'),
|
|
281
|
+
capabilities: context.capabilities.forModule('sandbox.core', {
|
|
282
|
+
provides: [],
|
|
283
|
+
requires: [],
|
|
284
|
+
}),
|
|
285
|
+
metrics: createModuleMetrics('sandbox.core'),
|
|
78
286
|
}),
|
|
79
287
|
moduleId: 'sandbox.core',
|
|
80
288
|
},
|
|
289
|
+
{
|
|
290
|
+
...search_core({
|
|
291
|
+
...context,
|
|
292
|
+
agentDefinitions: context.agentDefinitions.forModule('search.core'),
|
|
293
|
+
dataClasses: context.dataClasses.forModule('search.core'),
|
|
294
|
+
capabilities: context.capabilities.forModule('search.core', {
|
|
295
|
+
provides: ['search.providers.v1'],
|
|
296
|
+
requires: [],
|
|
297
|
+
}),
|
|
298
|
+
metrics: createModuleMetrics('search.core'),
|
|
299
|
+
}),
|
|
300
|
+
moduleId: 'search.core',
|
|
301
|
+
},
|
|
81
302
|
{
|
|
82
303
|
...users_core({
|
|
83
304
|
...context,
|
|
84
305
|
agentDefinitions: context.agentDefinitions.forModule('users.core'),
|
|
306
|
+
dataClasses: context.dataClasses.forModule('users.core'),
|
|
307
|
+
capabilities: context.capabilities.forModule('users.core', {
|
|
308
|
+
provides: [],
|
|
309
|
+
requires: [
|
|
310
|
+
{ id: 'search.providers.v1', optional: true },
|
|
311
|
+
{ id: 'import.ports.v1', optional: true },
|
|
312
|
+
{ id: 'exports.lists.v1', optional: true },
|
|
313
|
+
],
|
|
314
|
+
}),
|
|
315
|
+
metrics: createModuleMetrics('users.core'),
|
|
85
316
|
}),
|
|
86
317
|
moduleId: 'users.core',
|
|
87
318
|
},
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { defineEndpoint } from '@flowdular/sdk/server';
|
|
2
|
+
import type { ConfiguredDatabaseProvider } from '@flowdular/sdk/database';
|
|
3
|
+
|
|
4
|
+
/* Liveness only: it proves the process answers and touches nothing else, so a
|
|
5
|
+
container probe never fails because the database is busy. */
|
|
6
|
+
export const healthEndpoint = defineEndpoint({
|
|
7
|
+
id: 'system.health',
|
|
8
|
+
path: '/api/health',
|
|
9
|
+
methods: ['GET'],
|
|
10
|
+
access: { kind: 'public' },
|
|
11
|
+
handler: ({ requestId }) =>
|
|
12
|
+
Response.json(
|
|
13
|
+
{ status: 'ok', service: 'flowdular', requestId },
|
|
14
|
+
{ headers: { 'cache-control': 'no-store' } },
|
|
15
|
+
),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export function createReadinessEndpoint(databases: ConfiguredDatabaseProvider) {
|
|
19
|
+
return defineEndpoint({
|
|
20
|
+
id: 'system.ready',
|
|
21
|
+
path: '/api/ready',
|
|
22
|
+
methods: ['GET'],
|
|
23
|
+
access: { kind: 'public' },
|
|
24
|
+
handler: async ({ requestId }) => {
|
|
25
|
+
try {
|
|
26
|
+
const database = await databases.check();
|
|
27
|
+
return Response.json(
|
|
28
|
+
{ status: 'ready', service: 'flowdular', requestId, database },
|
|
29
|
+
{ headers: { 'cache-control': 'no-store' } },
|
|
30
|
+
);
|
|
31
|
+
} catch {
|
|
32
|
+
return Response.json(
|
|
33
|
+
{
|
|
34
|
+
status: 'unavailable',
|
|
35
|
+
service: 'flowdular',
|
|
36
|
+
requestId,
|
|
37
|
+
database: { adapter: databases.adapter, status: 'unavailable' },
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
status: 503,
|
|
41
|
+
headers: { 'cache-control': 'no-store', 'retry-after': '1' },
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|