@xemahq/kernel-contracts 0.1.0 → 0.2.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/LICENSE +201 -0
- package/dist/agent-tool-inquiry/index.d.ts +2 -0
- package/dist/agent-tool-inquiry/index.d.ts.map +1 -0
- package/dist/agent-tool-inquiry/index.js +18 -0
- package/dist/agent-tool-inquiry/index.js.map +1 -0
- package/dist/agent-tool-inquiry/lib/agent-tool-inquiry.d.ts +43 -0
- package/dist/agent-tool-inquiry/lib/agent-tool-inquiry.d.ts.map +1 -0
- package/dist/agent-tool-inquiry/lib/agent-tool-inquiry.js +32 -0
- package/dist/agent-tool-inquiry/lib/agent-tool-inquiry.js.map +1 -0
- package/dist/agent-workspace/awp-spec.json +1 -1
- package/dist/app-runtime/index.d.ts +9 -0
- package/dist/app-runtime/index.d.ts.map +1 -0
- package/dist/app-runtime/index.js +25 -0
- package/dist/app-runtime/index.js.map +1 -0
- package/dist/app-runtime/lib/app-client.d.ts +11 -0
- package/dist/app-runtime/lib/app-client.d.ts.map +1 -0
- package/dist/app-runtime/lib/app-client.js +23 -0
- package/dist/app-runtime/lib/app-client.js.map +1 -0
- package/dist/app-runtime/lib/app-lockfile.d.ts +12 -0
- package/dist/app-runtime/lib/app-lockfile.d.ts.map +1 -0
- package/dist/app-runtime/lib/app-lockfile.js +17 -0
- package/dist/app-runtime/lib/app-lockfile.js.map +1 -0
- package/dist/app-runtime/lib/app.d.ts +26 -0
- package/dist/app-runtime/lib/app.d.ts.map +1 -0
- package/dist/app-runtime/lib/app.js +31 -0
- package/dist/app-runtime/lib/app.js.map +1 -0
- package/dist/app-runtime/lib/audience-policy.d.ts +31 -0
- package/dist/app-runtime/lib/audience-policy.d.ts.map +1 -0
- package/dist/app-runtime/lib/audience-policy.js +38 -0
- package/dist/app-runtime/lib/audience-policy.js.map +1 -0
- package/dist/app-runtime/lib/biome-install.d.ts +9 -0
- package/dist/app-runtime/lib/biome-install.d.ts.map +1 -0
- package/dist/app-runtime/lib/biome-install.js +13 -0
- package/dist/app-runtime/lib/biome-install.js.map +1 -0
- package/dist/app-runtime/lib/branding-config.d.ts +9 -0
- package/dist/app-runtime/lib/branding-config.d.ts.map +1 -0
- package/dist/app-runtime/lib/branding-config.js +24 -0
- package/dist/app-runtime/lib/branding-config.js.map +1 -0
- package/dist/app-runtime/lib/delegated-session.d.ts +15 -0
- package/dist/app-runtime/lib/delegated-session.d.ts.map +1 -0
- package/dist/app-runtime/lib/delegated-session.js +29 -0
- package/dist/app-runtime/lib/delegated-session.js.map +1 -0
- package/dist/app-runtime/lib/external-subject.d.ts +9 -0
- package/dist/app-runtime/lib/external-subject.d.ts.map +1 -0
- package/dist/app-runtime/lib/external-subject.js +19 -0
- package/dist/app-runtime/lib/external-subject.js.map +1 -0
- package/dist/connector/index.d.ts +9 -0
- package/dist/connector/index.d.ts.map +1 -0
- package/dist/connector/index.js +25 -0
- package/dist/connector/index.js.map +1 -0
- package/dist/connector/lib/adapter-kind.d.ts +8 -0
- package/dist/connector/lib/adapter-kind.d.ts.map +1 -0
- package/dist/connector/lib/adapter-kind.js +14 -0
- package/dist/connector/lib/adapter-kind.js.map +1 -0
- package/dist/connector/lib/capability-refs.d.ts +14 -0
- package/dist/connector/lib/capability-refs.d.ts.map +1 -0
- package/dist/connector/lib/capability-refs.js +15 -0
- package/dist/connector/lib/capability-refs.js.map +1 -0
- package/dist/connector/lib/capability.d.ts +18 -0
- package/dist/connector/lib/capability.d.ts.map +1 -0
- package/dist/connector/lib/capability.js +24 -0
- package/dist/connector/lib/capability.js.map +1 -0
- package/dist/connector/lib/credential-kind.d.ts +42 -0
- package/dist/connector/lib/credential-kind.d.ts.map +1 -0
- package/dist/connector/lib/credential-kind.js +26 -0
- package/dist/connector/lib/credential-kind.js.map +1 -0
- package/dist/connector/lib/envelope-schema.d.ts +6 -0
- package/dist/connector/lib/envelope-schema.d.ts.map +1 -0
- package/dist/connector/lib/envelope-schema.js +150 -0
- package/dist/connector/lib/envelope-schema.js.map +1 -0
- package/dist/connector/lib/filter-expr-schema.d.ts +4 -0
- package/dist/connector/lib/filter-expr-schema.d.ts.map +1 -0
- package/dist/connector/lib/filter-expr-schema.js +65 -0
- package/dist/connector/lib/filter-expr-schema.js.map +1 -0
- package/dist/connector/lib/filter-expr-validate.d.ts +10 -0
- package/dist/connector/lib/filter-expr-validate.d.ts.map +1 -0
- package/dist/connector/lib/filter-expr-validate.js +58 -0
- package/dist/connector/lib/filter-expr-validate.js.map +1 -0
- package/dist/connector/lib/filter-expr.d.ts +49 -0
- package/dist/connector/lib/filter-expr.d.ts.map +1 -0
- package/dist/connector/lib/filter-expr.js +135 -0
- package/dist/connector/lib/filter-expr.js.map +1 -0
- package/dist/connector/lib/onboarding-manifest.d.ts +45 -0
- package/dist/connector/lib/onboarding-manifest.d.ts.map +1 -0
- package/dist/connector/lib/onboarding-manifest.js +30 -0
- package/dist/connector/lib/onboarding-manifest.js.map +1 -0
- package/dist/document-render/index.d.ts +7 -0
- package/dist/document-render/index.d.ts.map +1 -0
- package/dist/document-render/index.js +23 -0
- package/dist/document-render/index.js.map +1 -0
- package/dist/document-render/lib/measure-layout.d.ts +44 -0
- package/dist/document-render/lib/measure-layout.d.ts.map +1 -0
- package/dist/document-render/lib/measure-layout.js +16 -0
- package/dist/document-render/lib/measure-layout.js.map +1 -0
- package/dist/document-render/lib/render-enums.d.ts +18 -0
- package/dist/document-render/lib/render-enums.d.ts.map +1 -0
- package/dist/document-render/lib/render-enums.js +24 -0
- package/dist/document-render/lib/render-enums.js.map +1 -0
- package/dist/document-render/lib/render-record.d.ts +22 -0
- package/dist/document-render/lib/render-record.d.ts.map +1 -0
- package/dist/document-render/lib/render-record.js +3 -0
- package/dist/document-render/lib/render-record.js.map +1 -0
- package/dist/document-render/lib/render-request.d.ts +24 -0
- package/dist/document-render/lib/render-request.d.ts.map +1 -0
- package/dist/document-render/lib/render-request.js +12 -0
- package/dist/document-render/lib/render-request.js.map +1 -0
- package/dist/document-render/lib/render-source.d.ts +43 -0
- package/dist/document-render/lib/render-source.d.ts.map +1 -0
- package/dist/document-render/lib/render-source.js +31 -0
- package/dist/document-render/lib/render-source.js.map +1 -0
- package/dist/document-render/lib/xema-prompt.d.ts +11 -0
- package/dist/document-render/lib/xema-prompt.d.ts.map +1 -0
- package/dist/document-render/lib/xema-prompt.js +46 -0
- package/dist/document-render/lib/xema-prompt.js.map +1 -0
- package/dist/inquiry/index.d.ts +7 -0
- package/dist/inquiry/index.d.ts.map +1 -0
- package/dist/inquiry/index.js +23 -0
- package/dist/inquiry/index.js.map +1 -0
- package/dist/inquiry/lib/enums.d.ts +36 -0
- package/dist/inquiry/lib/enums.d.ts.map +1 -0
- package/dist/inquiry/lib/enums.js +45 -0
- package/dist/inquiry/lib/enums.js.map +1 -0
- package/dist/inquiry/lib/inquiry.d.ts +332 -0
- package/dist/inquiry/lib/inquiry.d.ts.map +1 -0
- package/dist/inquiry/lib/inquiry.js +102 -0
- package/dist/inquiry/lib/inquiry.js.map +1 -0
- package/dist/inquiry/lib/kind-registry.d.ts +14 -0
- package/dist/inquiry/lib/kind-registry.d.ts.map +1 -0
- package/dist/inquiry/lib/kind-registry.js +24 -0
- package/dist/inquiry/lib/kind-registry.js.map +1 -0
- package/dist/inquiry/lib/policy.d.ts +19 -0
- package/dist/inquiry/lib/policy.d.ts.map +1 -0
- package/dist/inquiry/lib/policy.js +21 -0
- package/dist/inquiry/lib/policy.js.map +1 -0
- package/dist/inquiry/lib/recipient.d.ts +111 -0
- package/dist/inquiry/lib/recipient.d.ts.map +1 -0
- package/dist/inquiry/lib/recipient.js +64 -0
- package/dist/inquiry/lib/recipient.js.map +1 -0
- package/dist/inquiry/lib/workflow-verdict-evaluator.d.ts +15 -0
- package/dist/inquiry/lib/workflow-verdict-evaluator.d.ts.map +1 -0
- package/dist/inquiry/lib/workflow-verdict-evaluator.js +145 -0
- package/dist/inquiry/lib/workflow-verdict-evaluator.js.map +1 -0
- package/dist/org-database/index.d.ts +5 -0
- package/dist/org-database/index.d.ts.map +1 -0
- package/dist/org-database/index.js +21 -0
- package/dist/org-database/index.js.map +1 -0
- package/dist/org-database/lib/db-result-event.d.ts +24 -0
- package/dist/org-database/lib/db-result-event.d.ts.map +1 -0
- package/dist/org-database/lib/db-result-event.js +3 -0
- package/dist/org-database/lib/db-result-event.js.map +1 -0
- package/dist/org-database/lib/driver.d.ts +43 -0
- package/dist/org-database/lib/driver.d.ts.map +1 -0
- package/dist/org-database/lib/driver.js +3 -0
- package/dist/org-database/lib/driver.js.map +1 -0
- package/dist/org-database/lib/enums.d.ts +41 -0
- package/dist/org-database/lib/enums.d.ts.map +1 -0
- package/dist/org-database/lib/enums.js +51 -0
- package/dist/org-database/lib/enums.js.map +1 -0
- package/dist/org-database/lib/migration-runner.d.ts +15 -0
- package/dist/org-database/lib/migration-runner.d.ts.map +1 -0
- package/dist/org-database/lib/migration-runner.js +3 -0
- package/dist/org-database/lib/migration-runner.js.map +1 -0
- package/dist/project-kit/index.d.ts +2 -0
- package/dist/project-kit/index.d.ts.map +1 -0
- package/dist/project-kit/index.js +18 -0
- package/dist/project-kit/index.js.map +1 -0
- package/dist/project-kit/lib/project-kit.d.ts +63 -0
- package/dist/project-kit/lib/project-kit.d.ts.map +1 -0
- package/dist/project-kit/lib/project-kit.js +32 -0
- package/dist/project-kit/lib/project-kit.js.map +1 -0
- package/dist/provisioning/index.d.ts +2 -0
- package/dist/provisioning/index.d.ts.map +1 -0
- package/dist/provisioning/index.js +18 -0
- package/dist/provisioning/index.js.map +1 -0
- package/dist/provisioning/lib/provisioning.d.ts +256 -0
- package/dist/provisioning/lib/provisioning.d.ts.map +1 -0
- package/dist/provisioning/lib/provisioning.js +221 -0
- package/dist/provisioning/lib/provisioning.js.map +1 -0
- package/dist/worker-runtime/index.d.ts +6 -0
- package/dist/worker-runtime/index.d.ts.map +1 -0
- package/dist/worker-runtime/index.js +22 -0
- package/dist/worker-runtime/index.js.map +1 -0
- package/dist/worker-runtime/lib/capabilities.d.ts +22 -0
- package/dist/worker-runtime/lib/capabilities.d.ts.map +1 -0
- package/dist/worker-runtime/lib/capabilities.js +3 -0
- package/dist/worker-runtime/lib/capabilities.js.map +1 -0
- package/dist/worker-runtime/lib/enums.d.ts +10 -0
- package/dist/worker-runtime/lib/enums.d.ts.map +1 -0
- package/dist/worker-runtime/lib/enums.js +15 -0
- package/dist/worker-runtime/lib/enums.js.map +1 -0
- package/dist/worker-runtime/lib/messages.d.ts +33 -0
- package/dist/worker-runtime/lib/messages.d.ts.map +1 -0
- package/dist/worker-runtime/lib/messages.js +3 -0
- package/dist/worker-runtime/lib/messages.js.map +1 -0
- package/dist/worker-runtime/lib/runtime.d.ts +35 -0
- package/dist/worker-runtime/lib/runtime.d.ts.map +1 -0
- package/dist/worker-runtime/lib/runtime.js +3 -0
- package/dist/worker-runtime/lib/runtime.js.map +1 -0
- package/dist/worker-runtime/lib/schemas.d.ts +87 -0
- package/dist/worker-runtime/lib/schemas.d.ts.map +1 -0
- package/dist/worker-runtime/lib/schemas.js +57 -0
- package/dist/worker-runtime/lib/schemas.js.map +1 -0
- package/dist/workspace-storage/index.d.ts +4 -0
- package/dist/workspace-storage/index.d.ts.map +1 -0
- package/dist/workspace-storage/index.js +20 -0
- package/dist/workspace-storage/index.js.map +1 -0
- package/dist/workspace-storage/lib/enums.d.ts +34 -0
- package/dist/workspace-storage/lib/enums.d.ts.map +1 -0
- package/dist/workspace-storage/lib/enums.js +42 -0
- package/dist/workspace-storage/lib/enums.js.map +1 -0
- package/dist/workspace-storage/lib/schemas.d.ts +56 -0
- package/dist/workspace-storage/lib/schemas.d.ts.map +1 -0
- package/dist/workspace-storage/lib/schemas.js +59 -0
- package/dist/workspace-storage/lib/schemas.js.map +1 -0
- package/dist/workspace-storage/lib/types.d.ts +71 -0
- package/dist/workspace-storage/lib/types.d.ts.map +1 -0
- package/dist/workspace-storage/lib/types.js +3 -0
- package/dist/workspace-storage/lib/types.js.map +1 -0
- package/package.json +22 -153
- package/src/agent-composition/lib/composition-workspace.ts +1 -1
- package/src/agent-tool-inquiry/index.ts +16 -0
- package/src/agent-tool-inquiry/lib/agent-tool-inquiry.ts +82 -0
- package/src/agent-workspace/lib/workspace-spec.ts +1 -1
- package/src/app-runtime/index.ts +8 -0
- package/src/app-runtime/lib/app-client.ts +44 -0
- package/src/app-runtime/lib/app-lockfile.ts +54 -0
- package/src/app-runtime/lib/app.ts +84 -0
- package/src/app-runtime/lib/audience-policy.ts +87 -0
- package/src/app-runtime/lib/biome-install.ts +29 -0
- package/src/app-runtime/lib/branding-config.ts +54 -0
- package/src/app-runtime/lib/delegated-session.ts +69 -0
- package/src/app-runtime/lib/external-subject.ts +34 -0
- package/src/connector/index.ts +8 -0
- package/src/connector/lib/adapter-kind.ts +37 -0
- package/src/connector/lib/capability-refs.ts +29 -0
- package/src/connector/lib/capability.ts +38 -0
- package/src/connector/lib/credential-kind.ts +120 -0
- package/src/connector/lib/envelope-schema.ts +256 -0
- package/src/connector/lib/filter-expr-schema.ts +75 -0
- package/src/connector/lib/filter-expr-validate.ts +91 -0
- package/src/connector/lib/filter-expr.ts +208 -0
- package/src/connector/lib/onboarding-manifest.ts +167 -0
- package/src/document-render/index.ts +25 -0
- package/src/document-render/lib/measure-layout.ts +61 -0
- package/src/document-render/lib/render-enums.ts +49 -0
- package/src/document-render/lib/render-record.ts +38 -0
- package/src/document-render/lib/render-request.ts +16 -0
- package/src/document-render/lib/render-source.ts +44 -0
- package/src/document-render/lib/xema-prompt.ts +100 -0
- package/src/inquiry/index.ts +23 -0
- package/src/inquiry/lib/enums.ts +103 -0
- package/src/inquiry/lib/inquiry.ts +182 -0
- package/src/inquiry/lib/kind-registry.ts +57 -0
- package/src/inquiry/lib/policy.ts +27 -0
- package/src/inquiry/lib/recipient.ts +188 -0
- package/src/inquiry/lib/workflow-verdict-evaluator.ts +220 -0
- package/src/org-database/index.ts +4 -0
- package/src/org-database/lib/db-result-event.ts +59 -0
- package/src/org-database/lib/driver.ts +47 -0
- package/src/org-database/lib/enums.ts +51 -0
- package/src/org-database/lib/migration-runner.ts +17 -0
- package/src/project-kit/index.ts +17 -0
- package/src/project-kit/lib/project-kit.ts +227 -0
- package/src/provisioning/index.ts +17 -0
- package/src/provisioning/lib/provisioning.ts +499 -0
- package/src/worker-runtime/index.ts +14 -0
- package/src/worker-runtime/lib/capabilities.ts +58 -0
- package/src/worker-runtime/lib/enums.ts +33 -0
- package/src/worker-runtime/lib/messages.ts +49 -0
- package/src/worker-runtime/lib/runtime.ts +109 -0
- package/src/worker-runtime/lib/schemas.ts +72 -0
- package/src/workflow/lib/activity-outputs.ts +1 -1
- package/src/workflow/lib/compiled-run.ts +1 -1
- package/src/workflow/lib/compiled-workspace-manifest.ts +1 -1
- package/src/workflow/lib/model-ref.ts +1 -1
- package/src/workflow/lib/workspace-manifest-enums.ts +1 -1
- package/src/workspace-storage/index.ts +12 -0
- package/src/workspace-storage/lib/enums.ts +78 -0
- package/src/workspace-storage/lib/schemas.ts +75 -0
- package/src/workspace-storage/lib/types.ts +145 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Accepts:
|
|
5
|
+
* - 3- or 6-digit hex (e.g. `#0a0`, `#0a0a0a`)
|
|
6
|
+
* - 8-digit hex with alpha (e.g. `#0a0a0aff`)
|
|
7
|
+
* - `rgb(r, g, b)` / `rgba(r, g, b, a)` (whitespace-flexible)
|
|
8
|
+
*
|
|
9
|
+
* Kept deliberately tight: the App branding contract should never silently
|
|
10
|
+
* absorb a free-form string. Anything else (CSS custom properties, named
|
|
11
|
+
* colors, `hsl(...)`, etc.) belongs in `cssTokens` where the host CSS
|
|
12
|
+
* pipeline interprets it.
|
|
13
|
+
*/
|
|
14
|
+
const PRIMARY_COLOR_REGEX =
|
|
15
|
+
/^(?:#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})|rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*(?:,\s*(?:0|1|0?\.\d+)\s*)?\))$/;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* `BrandingConfig` — per-App visual branding (plan §5.1). Used by the
|
|
19
|
+
* public ingress (`app-runtime-api`) and any embed snippet to theme the
|
|
20
|
+
* audience-facing UI. The shape is intentionally minimal:
|
|
21
|
+
*
|
|
22
|
+
* - `displayName` is REQUIRED — every audience-facing surface needs a
|
|
23
|
+
* human-readable label; no silent fallback to the App slug.
|
|
24
|
+
* - `primaryColor` is validated against a strict hex / rgb(a) grammar.
|
|
25
|
+
* - `cssTokens` is the escape hatch for richer theming — keys map to CSS
|
|
26
|
+
* custom-property names (without the leading `--`); the host CSS
|
|
27
|
+
* pipeline interprets the values.
|
|
28
|
+
*/
|
|
29
|
+
export interface BrandingConfig {
|
|
30
|
+
displayName: string;
|
|
31
|
+
logoUrl?: string;
|
|
32
|
+
primaryColor?: string;
|
|
33
|
+
cssTokens?: Record<string, string>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const BrandingConfigSchema = z.object({
|
|
37
|
+
displayName: z.string().min(1, {
|
|
38
|
+
message: 'BrandingConfig.displayName must be a non-empty string.',
|
|
39
|
+
}),
|
|
40
|
+
logoUrl: z
|
|
41
|
+
.string()
|
|
42
|
+
.url({
|
|
43
|
+
message: 'BrandingConfig.logoUrl must be a valid URL.',
|
|
44
|
+
})
|
|
45
|
+
.optional(),
|
|
46
|
+
primaryColor: z
|
|
47
|
+
.string()
|
|
48
|
+
.regex(PRIMARY_COLOR_REGEX, {
|
|
49
|
+
message:
|
|
50
|
+
'BrandingConfig.primaryColor must be a hex (`#rgb`, `#rrggbb`, `#rrggbbaa`) or `rgb()` / `rgba()` value. Use `cssTokens` for richer theming.',
|
|
51
|
+
})
|
|
52
|
+
.optional(),
|
|
53
|
+
cssTokens: z.record(z.string().min(1), z.string().min(1)).optional(),
|
|
54
|
+
}) as z.ZodType<BrandingConfig>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
CapabilityRefSchema,
|
|
4
|
+
type CapabilityRef,
|
|
5
|
+
} from '../../capability';
|
|
6
|
+
import {
|
|
7
|
+
ExecutionEnvironmentRefSchema,
|
|
8
|
+
type ExecutionEnvironmentRef,
|
|
9
|
+
} from '../../execution-environment';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Claims carried by a delegated session token minted by `app-runtime-api`
|
|
13
|
+
* for an `ExternalSubject` audience (plan §5.2):
|
|
14
|
+
*
|
|
15
|
+
* ```
|
|
16
|
+
* sub = external-user:<externalId> (or anon:<random>)
|
|
17
|
+
* act = app:<appClientId>
|
|
18
|
+
* org = <orgId>
|
|
19
|
+
* project = <projectId>
|
|
20
|
+
* session = <sessionId>
|
|
21
|
+
* environment = <environmentId> (typically environment:public-session)
|
|
22
|
+
* capabilities = [<allowed capability refs>]
|
|
23
|
+
* exp = short
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* `exp` is a Unix-epoch second count (RFC 7519 `exp` claim shape) — the
|
|
27
|
+
* value MUST be a positive integer. Token minting is short-lived by design;
|
|
28
|
+
* downstream services MUST NOT extend it silently.
|
|
29
|
+
*
|
|
30
|
+
* `capabilities` is the closed, fully-resolved set the gateway will honor
|
|
31
|
+
* for the lifetime of this token — refs not in this list are denied at the
|
|
32
|
+
* gateway with no fallback (per the capability-protocol fail-fast rule).
|
|
33
|
+
*/
|
|
34
|
+
export interface DelegatedSessionClaims {
|
|
35
|
+
sub: string;
|
|
36
|
+
act: string;
|
|
37
|
+
org: string;
|
|
38
|
+
project: string;
|
|
39
|
+
session: string;
|
|
40
|
+
environment: ExecutionEnvironmentRef;
|
|
41
|
+
capabilities: CapabilityRef[];
|
|
42
|
+
exp: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const DelegatedSessionClaimsSchema = z.object({
|
|
46
|
+
sub: z.string().min(1, {
|
|
47
|
+
message:
|
|
48
|
+
'DelegatedSessionClaims.sub must be a non-empty subject identifier (e.g. `external-user:<id>` or `anon:<random>`).',
|
|
49
|
+
}),
|
|
50
|
+
act: z.string().min(1, {
|
|
51
|
+
message:
|
|
52
|
+
'DelegatedSessionClaims.act must be a non-empty actor identifier (e.g. `app:<appClientId>`).',
|
|
53
|
+
}),
|
|
54
|
+
org: z.string().min(1, {
|
|
55
|
+
message: 'DelegatedSessionClaims.org must be a non-empty orgId.',
|
|
56
|
+
}),
|
|
57
|
+
project: z.string().min(1, {
|
|
58
|
+
message: 'DelegatedSessionClaims.project must be a non-empty projectId.',
|
|
59
|
+
}),
|
|
60
|
+
session: z.string().min(1, {
|
|
61
|
+
message: 'DelegatedSessionClaims.session must be a non-empty sessionId.',
|
|
62
|
+
}),
|
|
63
|
+
environment: ExecutionEnvironmentRefSchema,
|
|
64
|
+
capabilities: z.array(CapabilityRefSchema),
|
|
65
|
+
exp: z.number().int().positive({
|
|
66
|
+
message:
|
|
67
|
+
'DelegatedSessionClaims.exp must be a positive Unix-epoch second count (RFC 7519 `exp`).',
|
|
68
|
+
}),
|
|
69
|
+
}) as z.ZodType<DelegatedSessionClaims>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `ExternalSubject` — an app-scoped, non-Xema identity (plan §5.2). Created
|
|
5
|
+
* when an `AudiencePolicy` of kind `ExternalSubject` mints a delegated
|
|
6
|
+
* session for an upstream user (OIDC / magic-link / anon). External
|
|
7
|
+
* subjects do NOT become Xema users — they are stored and referenced only
|
|
8
|
+
* by their `externalId` under the owning `appClientId`.
|
|
9
|
+
*
|
|
10
|
+
* `createdAt` is a strict ISO-8601 datetime string at the wire boundary —
|
|
11
|
+
* no implicit timezone, no Unix-epoch fallback.
|
|
12
|
+
*/
|
|
13
|
+
export interface ExternalSubject {
|
|
14
|
+
externalId: string;
|
|
15
|
+
appClientId: string;
|
|
16
|
+
createdAt: string;
|
|
17
|
+
metadata?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const ExternalSubjectSchema = z.object({
|
|
21
|
+
externalId: z.string().min(1, {
|
|
22
|
+
message: 'ExternalSubject.externalId must be a non-empty string.',
|
|
23
|
+
}),
|
|
24
|
+
appClientId: z.string().min(1, {
|
|
25
|
+
message: 'ExternalSubject.appClientId must be a non-empty string.',
|
|
26
|
+
}),
|
|
27
|
+
createdAt: z
|
|
28
|
+
.string()
|
|
29
|
+
.datetime({
|
|
30
|
+
message:
|
|
31
|
+
'ExternalSubject.createdAt must be a strict ISO-8601 datetime string.',
|
|
32
|
+
}),
|
|
33
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
34
|
+
}) as z.ZodType<ExternalSubject>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './lib/adapter-kind';
|
|
2
|
+
export * from './lib/capability';
|
|
3
|
+
export * from './lib/credential-kind';
|
|
4
|
+
export * from './lib/onboarding-manifest';
|
|
5
|
+
export * from './lib/envelope-schema';
|
|
6
|
+
export * from './lib/filter-expr';
|
|
7
|
+
export * from './lib/filter-expr-schema';
|
|
8
|
+
export * from './lib/filter-expr-validate';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in adapter kinds.
|
|
3
|
+
*
|
|
4
|
+
* An `AdapterKind` is a *category* of external system. Each kind ships a
|
|
5
|
+
* canonical envelope schema in its owning domain service (SCM →
|
|
6
|
+
* connector-gateway-api, TRACKER → backlog-api, DOCUMENTATION →
|
|
7
|
+
* knowledge-base-api). Providers (github, gitlab, jira, …) plug into
|
|
8
|
+
* a kind by mapping their raw events onto that canonical envelope.
|
|
9
|
+
*
|
|
10
|
+
* The set is *built-in-closed but biome-extensible*: biomes may
|
|
11
|
+
* contribute additional kinds via the future `AdapterContribution`
|
|
12
|
+
* registry (Phase 7). The closed enum below names only the kinds the
|
|
13
|
+
* platform ships out-of-the-box. Anything outside this list MUST be
|
|
14
|
+
* either a built-in plus a biome contribution, or routed through an
|
|
15
|
+
* opaque `AdapterKindRef` string captured below.
|
|
16
|
+
*/
|
|
17
|
+
export enum BuiltInAdapterKind {
|
|
18
|
+
Scm = 'scm',
|
|
19
|
+
Tracker = 'tracker',
|
|
20
|
+
Documentation = 'documentation',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Wire-typed reference to an adapter kind. Built-in kinds use their
|
|
25
|
+
* `BuiltInAdapterKind` slug; biome-contributed kinds use whatever slug
|
|
26
|
+
* the contributing biome registered (validated at boot by
|
|
27
|
+
* integration-adapters-api).
|
|
28
|
+
*
|
|
29
|
+
* Stored as a plain string so the persistence layer (Prisma) does not
|
|
30
|
+
* have to evolve when a biome introduces a new kind. The runtime
|
|
31
|
+
* registry is the authority on which slugs are currently known.
|
|
32
|
+
*/
|
|
33
|
+
export type AdapterKindRef = string;
|
|
34
|
+
|
|
35
|
+
export function isBuiltInAdapterKind(ref: AdapterKindRef): ref is BuiltInAdapterKind {
|
|
36
|
+
return (Object.values(BuiltInAdapterKind) as string[]).includes(ref);
|
|
37
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// ── Connector capability refs ──
|
|
3
|
+
//
|
|
4
|
+
// Typed string constants for the connector capabilities exposed by the
|
|
5
|
+
// capability gateway. Values are CapabilityRefs (see `@xemahq/capability-
|
|
6
|
+
// contracts`); they version like syscalls (`@1`, `@2`, ...) and the runtime
|
|
7
|
+
// MUST refuse to dispatch a major version it has not registered.
|
|
8
|
+
//
|
|
9
|
+
// Source of truth: plan §17.2-B item 2. This file is the registry seed; the
|
|
10
|
+
// `connector-gateway-api` capability dispatcher MAY consume it directly for
|
|
11
|
+
// `name`-side validation.
|
|
12
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
13
|
+
|
|
14
|
+
import type { CapabilityRef } from '../../capability';
|
|
15
|
+
|
|
16
|
+
export const CONNECTOR_CAPABILITY_REFS = Object.freeze({
|
|
17
|
+
ScmCreatePullRequest: 'connector:scm.create-pull-request@1' as CapabilityRef,
|
|
18
|
+
ScmMerge: 'connector:scm.merge@1' as CapabilityRef,
|
|
19
|
+
TrackerIssueCreate: 'connector:tracker.issue.create@1' as CapabilityRef,
|
|
20
|
+
TrackerIssueTransition:
|
|
21
|
+
'connector:tracker.issue.transition@1' as CapabilityRef,
|
|
22
|
+
DocsPublishPage: 'connector:docs.publish-page@1' as CapabilityRef,
|
|
23
|
+
DocsPageRead: 'connector:docs.page.read@1' as CapabilityRef,
|
|
24
|
+
ChatSendMessage: 'connector:chat.send-message@1' as CapabilityRef,
|
|
25
|
+
LlmInvoke: 'connector:llm.invoke@1' as CapabilityRef,
|
|
26
|
+
McpToolInvoke: 'connector:mcp.tool.invoke@1' as CapabilityRef,
|
|
27
|
+
} as const);
|
|
28
|
+
|
|
29
|
+
export type ConnectorCapabilityRefName = keyof typeof CONNECTOR_CAPABILITY_REFS;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability slugs a biome can request against an integration. The set
|
|
3
|
+
* is *closed and built-in for v1*. Biome-contributed AdapterKinds may
|
|
4
|
+
* register additional capability slugs at boot (validated against the
|
|
5
|
+
* `^[a-z]+(\.[a-z][a-z0-9-]*)+$` shape).
|
|
6
|
+
*
|
|
7
|
+
* Slugs are `<domain>.<verb>[-qualifier]`. The first segment maps to the
|
|
8
|
+
* AdapterKind family the capability applies to; the rest names the
|
|
9
|
+
* action. Closed enum values exist for the v1 built-in kinds so consent
|
|
10
|
+
* UX and ESLint rules can switch on them exhaustively.
|
|
11
|
+
*/
|
|
12
|
+
export enum BuiltInCapability {
|
|
13
|
+
ScmReadRepo = 'scm.read-repo',
|
|
14
|
+
ScmReadBranch = 'scm.read-branch',
|
|
15
|
+
ScmReadCommit = 'scm.read-commit',
|
|
16
|
+
ScmReadFile = 'scm.read-file',
|
|
17
|
+
ScmWritePrComment = 'scm.write-pr-comment',
|
|
18
|
+
ScmWriteCommitStatus = 'scm.write-commit-status',
|
|
19
|
+
TrackerReadIssue = 'tracker.read-issue',
|
|
20
|
+
TrackerWriteIssue = 'tracker.write-issue',
|
|
21
|
+
TrackerWriteComment = 'tracker.write-comment',
|
|
22
|
+
TrackerTransitionStatus = 'tracker.transition-status',
|
|
23
|
+
DocumentationReadPage = 'documentation.read-page',
|
|
24
|
+
DocumentationWritePage = 'documentation.write-page',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Capability slug at the wire boundary — a string for forward
|
|
29
|
+
* compatibility with biome-contributed AdapterKinds. Validate against
|
|
30
|
+
* the shape regex at manifest-parse time.
|
|
31
|
+
*/
|
|
32
|
+
export type CapabilitySlug = string;
|
|
33
|
+
|
|
34
|
+
export const CAPABILITY_SLUG_PATTERN = /^[a-z]+(\.[a-z][a-z0-9-]*)+$/;
|
|
35
|
+
|
|
36
|
+
export function isValidCapabilitySlug(slug: string): slug is CapabilitySlug {
|
|
37
|
+
return CAPABILITY_SLUG_PATTERN.test(slug);
|
|
38
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Closed enum of credential strategies the platform knows how to mint,
|
|
3
|
+
* cache, refresh and revoke. Biomes contributing new providers (Phase
|
|
4
|
+
* 7) MUST declare one of these — they never ship custom mint code.
|
|
5
|
+
*
|
|
6
|
+
* Adding a kind here is a one-line schema change plus a matching
|
|
7
|
+
* strategy implementation under
|
|
8
|
+
* `apps/integration-adapters-api/src/credentials/strategies/<kind>/`.
|
|
9
|
+
*/
|
|
10
|
+
export enum CredentialKind {
|
|
11
|
+
/** GitHub App / GitLab App style installation token (per-installation, 1h). */
|
|
12
|
+
AppInstall = 'app_install',
|
|
13
|
+
/** 3-legged OAuth user-delegated token with refresh-token rotation. */
|
|
14
|
+
OAuthUser = 'oauth_user',
|
|
15
|
+
/** 2-legged OAuth client-credentials grant. */
|
|
16
|
+
OAuthClient = 'oauth_client',
|
|
17
|
+
/** Long-lived personal access token. */
|
|
18
|
+
Pat = 'pat',
|
|
19
|
+
/** Generic API key. */
|
|
20
|
+
ApiKey = 'api_key',
|
|
21
|
+
/** Long-lived bot token (Slack / Discord style). */
|
|
22
|
+
BotToken = 'bot_token',
|
|
23
|
+
/** HTTP Basic auth credential. */
|
|
24
|
+
Basic = 'basic',
|
|
25
|
+
/** Provider-scoped restricted key (Stripe restricted keys, etc.). */
|
|
26
|
+
RestrictedKey = 'restricted_key',
|
|
27
|
+
/** AWS STS AssumeRoleWithWebIdentity using a workload-identity token. */
|
|
28
|
+
IamRole = 'iam_role',
|
|
29
|
+
/**
|
|
30
|
+
* No outbound credential — provider sends signed webhooks only. The
|
|
31
|
+
* resolver returns no token; only the webhook verifier is registered.
|
|
32
|
+
*/
|
|
33
|
+
SignatureOnly = 'signature_only',
|
|
34
|
+
/**
|
|
35
|
+
* SMTP wallet (one or more per org). Stored as a typed config blob —
|
|
36
|
+
* `host`, `port`, `username`, `password`, `tlsMode`, optional
|
|
37
|
+
* `fromAddress` and `fromName`. Resolved as `tokenType='header'` with
|
|
38
|
+
* the full config carried in `providerHints` so the SMTP send
|
|
39
|
+
* activity can hand it straight to nodemailer without re-decrypting.
|
|
40
|
+
*/
|
|
41
|
+
SmtpAuth = 'smtp_auth',
|
|
42
|
+
/**
|
|
43
|
+
* IMAP wallet (one or more per org). Same shape as SmtpAuth minus
|
|
44
|
+
* the sender fields. Resolver carries `host`, `port`, `username`,
|
|
45
|
+
* `password`, `tlsMode` in `providerHints` for imapflow.
|
|
46
|
+
*/
|
|
47
|
+
ImapAuth = 'imap_auth',
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Closed TLS-mode enum shared by SMTP + IMAP wallets. `auto` lets the
|
|
52
|
+
* client library pick the right mode for the configured port:
|
|
53
|
+
* - 465 / 993 → implicit TLS
|
|
54
|
+
* - 587 / 143 → STARTTLS (negotiated)
|
|
55
|
+
* - 25 (SMTP) → plain (warns; not recommended)
|
|
56
|
+
* `tls` / `starttls` / `plain` are the explicit overrides.
|
|
57
|
+
*/
|
|
58
|
+
export enum EmailTlsMode {
|
|
59
|
+
Auto = 'auto',
|
|
60
|
+
Tls = 'tls',
|
|
61
|
+
Starttls = 'starttls',
|
|
62
|
+
Plain = 'plain',
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Wire shape of the SMTP / IMAP wallet payload as carried in
|
|
67
|
+
* `MintedToken.providerHints`. The values are always plain strings on
|
|
68
|
+
* the wire — `port` is stringified so the platform-common decoder can
|
|
69
|
+
* round-trip through any envelope without losing the type. The send /
|
|
70
|
+
* fetch activities re-parse `port` to a number at use site.
|
|
71
|
+
*
|
|
72
|
+
* Sensitive fields (`password`) are returned by the resolver only;
|
|
73
|
+
* cache the minted token, not the wallet config, and never log it.
|
|
74
|
+
*/
|
|
75
|
+
export interface EmailWalletHints {
|
|
76
|
+
host: string;
|
|
77
|
+
port: string;
|
|
78
|
+
username: string;
|
|
79
|
+
password: string;
|
|
80
|
+
tlsMode: EmailTlsMode;
|
|
81
|
+
/** SMTP only — default sender address for the wallet. */
|
|
82
|
+
fromAddress?: string;
|
|
83
|
+
/** SMTP only — default sender name. */
|
|
84
|
+
fromName?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* A minted, ready-to-use token returned by `POST /credentials/resolve`.
|
|
89
|
+
* Provider-neutral by construction — `providerHints` carries any
|
|
90
|
+
* per-provider routing data (regional endpoint, app id, …) opaquely.
|
|
91
|
+
*/
|
|
92
|
+
export type MintedTokenType =
|
|
93
|
+
| 'bearer'
|
|
94
|
+
| 'basic'
|
|
95
|
+
| 'aws-sigv4'
|
|
96
|
+
| 'header'
|
|
97
|
+
/**
|
|
98
|
+
* Webhook-verifier-only: `accessToken` carries the HMAC shared
|
|
99
|
+
* secret. Callers MUST NOT send this anywhere outbound; the only
|
|
100
|
+
* intended use is local signature verification on inbound webhooks.
|
|
101
|
+
*/
|
|
102
|
+
| 'signature-only';
|
|
103
|
+
|
|
104
|
+
export interface MintedToken {
|
|
105
|
+
tokenType: MintedTokenType;
|
|
106
|
+
accessToken: string;
|
|
107
|
+
expiresAt: string | null;
|
|
108
|
+
expiresInSec: number | null;
|
|
109
|
+
providerHints: Readonly<Record<string, string>>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Reference to a concrete resource the credential mint is being asked
|
|
114
|
+
* to scope to. `type` identifies which `ResourceLister` produced it
|
|
115
|
+
* (e.g. `'repo'`, `'project'`, `'channel'`); `id` is provider-opaque.
|
|
116
|
+
*/
|
|
117
|
+
export interface ResourceRef {
|
|
118
|
+
type: string;
|
|
119
|
+
id: string;
|
|
120
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { BuiltInAdapterKind, type AdapterKindRef } from './adapter-kind';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Canonical envelope path schemas — per built-in `(AdapterKind, EntityKind)`.
|
|
5
|
+
*
|
|
6
|
+
* The dispatcher receives a canonical webhook envelope shaped by the
|
|
7
|
+
* domain service that owns the AdapterKind (connector-gateway-api,
|
|
8
|
+
* backlog-api, knowledge-base-api). At biome-manifest validation
|
|
9
|
+
* time we want to fail fast on `FilterExpr` predicates that reference
|
|
10
|
+
* `$envelope.someFieldThatDoesNotExist`, instead of silently
|
|
11
|
+
* evaluating to `false` at dispatch.
|
|
12
|
+
*
|
|
13
|
+
* The map is keyed by `(adapterKind, entityKind)`. When a webhook
|
|
14
|
+
* filter declares its target `entityKind` (Phase 7 manifest field),
|
|
15
|
+
* the cross-validator narrows path checking to that entry. Filters
|
|
16
|
+
* that omit `entityKind` fall back to the `UNION_ENTITY_KIND` entry,
|
|
17
|
+
* which collects every path across the adapter's entity kinds — over-
|
|
18
|
+
* permissive but still catches the common typo class.
|
|
19
|
+
*
|
|
20
|
+
* Updates: when a domain service adds/renames a payload field, the
|
|
21
|
+
* matching entry below MUST be updated in the same PR. `crossValidate-
|
|
22
|
+
* IntegrationContract` walks every biome's filter predicates against
|
|
23
|
+
* this map at biome-host boot, so stale entries surface as cross-
|
|
24
|
+
* validation failures with named paths.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Wildcard entityKind used when a `FilterExpr` predicate doesn't
|
|
29
|
+
* declare which entity kind it targets. Matches the union across all
|
|
30
|
+
* entity kinds the adapter owns.
|
|
31
|
+
*/
|
|
32
|
+
export const UNION_ENTITY_KIND = '*';
|
|
33
|
+
|
|
34
|
+
/** Inherited base envelope fields (defined on `IntegrationWebhookEnvelopeDto`). */
|
|
35
|
+
const BASE_ENVELOPE_PATHS = [
|
|
36
|
+
'provider',
|
|
37
|
+
'adapterKey',
|
|
38
|
+
'event',
|
|
39
|
+
'entityKind',
|
|
40
|
+
'deliveryId',
|
|
41
|
+
'occurredAt',
|
|
42
|
+
'correlationId',
|
|
43
|
+
'externalId',
|
|
44
|
+
'externalSpaceKey',
|
|
45
|
+
] as const;
|
|
46
|
+
|
|
47
|
+
// ── SCM per-entityKind payload paths ──
|
|
48
|
+
|
|
49
|
+
const SCM_PUSH_PATHS = [
|
|
50
|
+
'payload.repositoryCloneUrl',
|
|
51
|
+
'payload.repositoryFullName',
|
|
52
|
+
'payload.authorExternalId',
|
|
53
|
+
'payload.ref',
|
|
54
|
+
'payload.branch',
|
|
55
|
+
'payload.beforeSha',
|
|
56
|
+
'payload.afterSha',
|
|
57
|
+
'payload.commitCount',
|
|
58
|
+
'payload.commits',
|
|
59
|
+
'payload.commits.sha',
|
|
60
|
+
'payload.commits.message',
|
|
61
|
+
'payload.commits.authorExternalId',
|
|
62
|
+
'payload.commits.committedAt',
|
|
63
|
+
] as const;
|
|
64
|
+
|
|
65
|
+
const SCM_CHANGE_REQUEST_PATHS = [
|
|
66
|
+
'payload.repositoryCloneUrl',
|
|
67
|
+
'payload.repositoryFullName',
|
|
68
|
+
'payload.authorExternalId',
|
|
69
|
+
'payload.title',
|
|
70
|
+
'payload.description',
|
|
71
|
+
'payload.state',
|
|
72
|
+
'payload.sourceBranch',
|
|
73
|
+
'payload.targetBranch',
|
|
74
|
+
'payload.headSha',
|
|
75
|
+
'payload.mergeCommitSha',
|
|
76
|
+
] as const;
|
|
77
|
+
|
|
78
|
+
const SCM_ISSUE_PATHS = [
|
|
79
|
+
'payload.repositoryCloneUrl',
|
|
80
|
+
'payload.repositoryFullName',
|
|
81
|
+
'payload.authorExternalId',
|
|
82
|
+
'payload.title',
|
|
83
|
+
'payload.description',
|
|
84
|
+
'payload.state',
|
|
85
|
+
'payload.labels',
|
|
86
|
+
] as const;
|
|
87
|
+
|
|
88
|
+
const SCM_REPOSITORY_PATHS = [
|
|
89
|
+
'payload.repositoryCloneUrl',
|
|
90
|
+
'payload.repositoryFullName',
|
|
91
|
+
'payload.action',
|
|
92
|
+
'payload.visibility',
|
|
93
|
+
'payload.previousVisibility',
|
|
94
|
+
'payload.previousRepositoryCloneUrl',
|
|
95
|
+
'payload.previousRepositoryFullName',
|
|
96
|
+
] as const;
|
|
97
|
+
|
|
98
|
+
const SCM_INSTALLATION_PATHS = [
|
|
99
|
+
'payload.installationId',
|
|
100
|
+
'payload.action',
|
|
101
|
+
'payload.accountLogin',
|
|
102
|
+
'payload.affectedRepositoryFullNames',
|
|
103
|
+
] as const;
|
|
104
|
+
|
|
105
|
+
// ── Tracker per-entityKind payload paths ──
|
|
106
|
+
|
|
107
|
+
const TRACKER_ITEM_PATHS = [
|
|
108
|
+
'payload.title',
|
|
109
|
+
'payload.description',
|
|
110
|
+
'payload.type',
|
|
111
|
+
'payload.status',
|
|
112
|
+
'payload.priority',
|
|
113
|
+
'payload.tags',
|
|
114
|
+
'payload.ownerDomain',
|
|
115
|
+
] as const;
|
|
116
|
+
|
|
117
|
+
const TRACKER_COMMENT_PATHS = [
|
|
118
|
+
'payload.itemExternalId',
|
|
119
|
+
'payload.content',
|
|
120
|
+
'payload.authorId',
|
|
121
|
+
'payload.authorType',
|
|
122
|
+
] as const;
|
|
123
|
+
|
|
124
|
+
// ── Documentation per-entityKind payload paths ──
|
|
125
|
+
|
|
126
|
+
const DOC_PAGE_PATHS = [
|
|
127
|
+
'payload.slug',
|
|
128
|
+
'payload.title',
|
|
129
|
+
'payload.content',
|
|
130
|
+
'payload.contentType',
|
|
131
|
+
'payload.externalParentId',
|
|
132
|
+
] as const;
|
|
133
|
+
|
|
134
|
+
const DOC_SPACE_PATHS = [
|
|
135
|
+
'payload.slug',
|
|
136
|
+
'payload.title',
|
|
137
|
+
'payload.description',
|
|
138
|
+
] as const;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Per-`(adapterKind, entityKind)` allowed `$envelope.*` paths. The
|
|
142
|
+
* `'*'` entityKind entry is the union across every kind for that
|
|
143
|
+
* adapter — used when a filter omits `entityKind` (today's default).
|
|
144
|
+
*/
|
|
145
|
+
const ENVELOPE_PATHS_BY_KIND_BY_ENTITY = new Map<
|
|
146
|
+
AdapterKindRef,
|
|
147
|
+
Map<string, ReadonlySet<string>>
|
|
148
|
+
>();
|
|
149
|
+
|
|
150
|
+
registerEnvelopeSchema(BuiltInAdapterKind.Scm, {
|
|
151
|
+
push: SCM_PUSH_PATHS,
|
|
152
|
+
change_request: SCM_CHANGE_REQUEST_PATHS,
|
|
153
|
+
issue: SCM_ISSUE_PATHS,
|
|
154
|
+
repository: SCM_REPOSITORY_PATHS,
|
|
155
|
+
installation: SCM_INSTALLATION_PATHS,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
registerEnvelopeSchema(BuiltInAdapterKind.Tracker, {
|
|
159
|
+
item: TRACKER_ITEM_PATHS,
|
|
160
|
+
comment: TRACKER_COMMENT_PATHS,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
registerEnvelopeSchema(BuiltInAdapterKind.Documentation, {
|
|
164
|
+
page: DOC_PAGE_PATHS,
|
|
165
|
+
space: DOC_SPACE_PATHS,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Register the per-entityKind permitted `$envelope.*` paths for a
|
|
170
|
+
* biome-contributed AdapterKind (Phase 7). Built-in kinds are pre-
|
|
171
|
+
* registered above. Re-registering an existing kind REPLACES its
|
|
172
|
+
* entry set — `integration-adapters-api`'s registry is the authority,
|
|
173
|
+
* so biome upgrades surface here.
|
|
174
|
+
*
|
|
175
|
+
* Each entry in `perEntityKind` lists the payload paths (without the
|
|
176
|
+
* `$envelope.` prefix, without the base envelope fields — those are
|
|
177
|
+
* implicitly included). The `'*'` union entry is derived automatically.
|
|
178
|
+
*/
|
|
179
|
+
export function registerEnvelopeSchema(
|
|
180
|
+
adapterKind: AdapterKindRef,
|
|
181
|
+
perEntityKind: Readonly<Record<string, readonly string[]>>,
|
|
182
|
+
): void {
|
|
183
|
+
const perEntity = new Map<string, ReadonlySet<string>>();
|
|
184
|
+
const unionSet = new Set<string>(BASE_ENVELOPE_PATHS);
|
|
185
|
+
for (const [entityKind, paths] of Object.entries(perEntityKind)) {
|
|
186
|
+
const withBase = new Set<string>([...BASE_ENVELOPE_PATHS, ...paths]);
|
|
187
|
+
perEntity.set(entityKind, withBase);
|
|
188
|
+
for (const path of paths) unionSet.add(path);
|
|
189
|
+
}
|
|
190
|
+
perEntity.set(UNION_ENTITY_KIND, unionSet);
|
|
191
|
+
ENVELOPE_PATHS_BY_KIND_BY_ENTITY.set(adapterKind, perEntity);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Returns the set of permitted `$envelope.*` paths for the given
|
|
196
|
+
* `(adapterKind, entityKind)`. `entityKind === undefined` means
|
|
197
|
+
* "union across every entity kind under this adapter".
|
|
198
|
+
*
|
|
199
|
+
* `undefined` return: the adapter kind isn't registered (biome-
|
|
200
|
+
* contributed kind whose adapter hasn't loaded yet) — callers should
|
|
201
|
+
* skip validation rather than fail.
|
|
202
|
+
*/
|
|
203
|
+
export function getEnvelopeSchema(
|
|
204
|
+
adapterKind: AdapterKindRef,
|
|
205
|
+
entityKind?: string,
|
|
206
|
+
): ReadonlySet<string> | undefined {
|
|
207
|
+
const perEntity = ENVELOPE_PATHS_BY_KIND_BY_ENTITY.get(adapterKind);
|
|
208
|
+
if (!perEntity) return undefined;
|
|
209
|
+
return perEntity.get(entityKind ?? UNION_ENTITY_KIND);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* True iff `path` is a permitted reference under `$envelope.*` for
|
|
214
|
+
* the given `(adapterKind, entityKind)`. Numeric path segments
|
|
215
|
+
* (array indices) are normalized before lookup —
|
|
216
|
+
* `payload.commits.0.sha` matches `payload.commits.sha`.
|
|
217
|
+
*
|
|
218
|
+
* When `entityKind` is omitted, validates against the union across
|
|
219
|
+
* every entity kind for the adapter.
|
|
220
|
+
*
|
|
221
|
+
* Returns `true` when the adapter kind is unregistered OR when an
|
|
222
|
+
* `entityKind` is passed but the registered schema doesn't know it —
|
|
223
|
+
* biome-contributed kinds without a loaded schema don't break
|
|
224
|
+
* validation (the cross-validator surfaces the missing-schema case
|
|
225
|
+
* separately).
|
|
226
|
+
*/
|
|
227
|
+
export function isAllowedEnvelopePath(
|
|
228
|
+
adapterKind: AdapterKindRef,
|
|
229
|
+
path: string,
|
|
230
|
+
entityKind?: string,
|
|
231
|
+
): boolean {
|
|
232
|
+
const schema = getEnvelopeSchema(adapterKind, entityKind);
|
|
233
|
+
if (!schema) {
|
|
234
|
+
// Either the adapter kind isn't registered, or the registered
|
|
235
|
+
// schema doesn't recognize the entityKind. Either way, fall back
|
|
236
|
+
// to the union (if any) so an unknown entityKind doesn't bomb.
|
|
237
|
+
if (entityKind !== undefined) {
|
|
238
|
+
const unionFallback = getEnvelopeSchema(adapterKind);
|
|
239
|
+
if (unionFallback) return unionFallback.has(normalizeEnvelopePath(path));
|
|
240
|
+
}
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
return schema.has(normalizeEnvelopePath(path));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Strip numeric-index segments from a dot-delimited path so the
|
|
248
|
+
* schema lookup sees the structural shape. `commits.0.sha` →
|
|
249
|
+
* `commits.sha`.
|
|
250
|
+
*/
|
|
251
|
+
function normalizeEnvelopePath(path: string): string {
|
|
252
|
+
return path
|
|
253
|
+
.split('.')
|
|
254
|
+
.filter((segment) => !/^\d+$/.test(segment))
|
|
255
|
+
.join('.');
|
|
256
|
+
}
|