@ankhorage/contracts 14.0.0 → 15.0.0
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/CHANGELOG.md +31 -0
- package/README.md +10 -2
- package/dist/appManifest/apis.d.ts +1 -0
- package/dist/appManifest/apis.d.ts.map +1 -1
- package/dist/appManifest/apis.js +17 -14
- package/dist/appManifest/apis.js.map +1 -1
- package/dist/appManifest/bindings.d.ts +3 -0
- package/dist/appManifest/bindings.d.ts.map +1 -1
- package/dist/appManifest/bindings.js +17 -1
- package/dist/appManifest/bindings.js.map +1 -1
- package/dist/appManifest/constants.d.ts +18 -0
- package/dist/appManifest/constants.d.ts.map +1 -0
- package/dist/appManifest/constants.js +18 -0
- package/dist/appManifest/constants.js.map +1 -0
- package/dist/appManifest/data.d.ts +4 -0
- package/dist/appManifest/data.d.ts.map +1 -1
- package/dist/appManifest/data.js +22 -3
- package/dist/appManifest/data.js.map +1 -1
- package/dist/appManifest/dataSources.d.ts +1 -0
- package/dist/appManifest/dataSources.d.ts.map +1 -1
- package/dist/appManifest/dataSources.js +7 -6
- package/dist/appManifest/dataSources.js.map +1 -1
- package/dist/appManifest/deploy.d.ts +1 -0
- package/dist/appManifest/deploy.d.ts.map +1 -1
- package/dist/appManifest/deploy.js +16 -13
- package/dist/appManifest/deploy.js.map +1 -1
- package/dist/appManifest/icon.d.ts.map +1 -1
- package/dist/appManifest/icon.js +2 -1
- package/dist/appManifest/icon.js.map +1 -1
- package/dist/appManifest/isAppManifest.d.ts +4 -0
- package/dist/appManifest/isAppManifest.d.ts.map +1 -0
- package/dist/appManifest/isAppManifest.js +69 -0
- package/dist/appManifest/isAppManifest.js.map +1 -0
- package/dist/appManifest/isAppStateSpec.d.ts +4 -0
- package/dist/appManifest/isAppStateSpec.d.ts.map +1 -0
- package/dist/appManifest/isAppStateSpec.js +9 -0
- package/dist/appManifest/isAppStateSpec.js.map +1 -0
- package/dist/appManifest/isManifestValue.d.ts +3 -0
- package/dist/appManifest/isManifestValue.d.ts.map +1 -0
- package/dist/appManifest/isManifestValue.js +15 -0
- package/dist/appManifest/isManifestValue.js.map +1 -0
- package/dist/appManifest/media.d.ts +1 -0
- package/dist/appManifest/media.d.ts.map +1 -1
- package/dist/appManifest/media.js +10 -8
- package/dist/appManifest/media.js.map +1 -1
- package/dist/appManifest/navigator.d.ts.map +1 -1
- package/dist/appManifest/navigator.js +7 -6
- package/dist/appManifest/navigator.js.map +1 -1
- package/dist/appManifest/navigatorOptions.d.ts +0 -2
- package/dist/appManifest/navigatorOptions.d.ts.map +1 -1
- package/dist/appManifest/navigatorOptions.js +8 -12
- package/dist/appManifest/navigatorOptions.js.map +1 -1
- package/dist/appManifest/parseAppManifest.d.ts +10 -0
- package/dist/appManifest/parseAppManifest.d.ts.map +1 -0
- package/dist/appManifest/parseAppManifest.js +14 -0
- package/dist/appManifest/parseAppManifest.js.map +1 -0
- package/dist/appManifest/screens.d.ts +4 -0
- package/dist/appManifest/screens.d.ts.map +1 -1
- package/dist/appManifest/screens.js +14 -2
- package/dist/appManifest/screens.js.map +1 -1
- package/dist/appManifest.d.ts +3 -18
- package/dist/appManifest.d.ts.map +1 -1
- package/dist/appManifest.js +2 -80
- package/dist/appManifest.js.map +1 -1
- package/dist/auth.d.ts +3 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js.map +1 -1
- package/dist/deploy.d.ts +0 -9
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +0 -8
- package/dist/deploy.js.map +1 -1
- package/dist/environments.d.ts +4 -0
- package/dist/environments.d.ts.map +1 -0
- package/dist/environments.js +3 -0
- package/dist/environments.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/infra/constants.d.ts +91 -0
- package/dist/infra/constants.d.ts.map +1 -0
- package/dist/infra/constants.js +91 -0
- package/dist/infra/constants.js.map +1 -0
- package/dist/infra/infraFields.d.ts +12 -0
- package/dist/infra/infraFields.d.ts.map +1 -0
- package/dist/infra/infraFields.js +14 -0
- package/dist/infra/infraFields.js.map +1 -0
- package/dist/infra/isInfraAdapterDescriptor.d.ts +4 -0
- package/dist/infra/isInfraAdapterDescriptor.d.ts.map +1 -0
- package/dist/infra/isInfraAdapterDescriptor.js +31 -0
- package/dist/infra/isInfraAdapterDescriptor.js.map +1 -0
- package/dist/infra/isInfraAuthSpec.d.ts +4 -0
- package/dist/infra/isInfraAuthSpec.d.ts.map +1 -0
- package/dist/infra/isInfraAuthSpec.js +75 -0
- package/dist/infra/isInfraAuthSpec.js.map +1 -0
- package/dist/infra/isInfraCredentialRef.d.ts +3 -0
- package/dist/infra/isInfraCredentialRef.d.ts.map +1 -0
- package/dist/infra/isInfraCredentialRef.js +10 -0
- package/dist/infra/isInfraCredentialRef.js.map +1 -0
- package/dist/infra/isInfraDeploymentSpec.d.ts +4 -0
- package/dist/infra/isInfraDeploymentSpec.d.ts.map +1 -0
- package/dist/infra/isInfraDeploymentSpec.js +66 -0
- package/dist/infra/isInfraDeploymentSpec.js.map +1 -0
- package/dist/infra/isInfraEnvironmentSpec.d.ts +4 -0
- package/dist/infra/isInfraEnvironmentSpec.d.ts.map +1 -0
- package/dist/infra/isInfraEnvironmentSpec.js +82 -0
- package/dist/infra/isInfraEnvironmentSpec.js.map +1 -0
- package/dist/infra/isInfraManifest.d.ts +4 -0
- package/dist/infra/isInfraManifest.d.ts.map +1 -0
- package/dist/infra/isInfraManifest.js +23 -0
- package/dist/infra/isInfraManifest.js.map +1 -0
- package/dist/infra/isInfraShape.d.ts +3 -0
- package/dist/infra/isInfraShape.d.ts.map +1 -0
- package/dist/infra/isInfraShape.js +10 -0
- package/dist/infra/isInfraShape.js.map +1 -0
- package/dist/infra/isInfraWorkloadHealth.d.ts +3 -0
- package/dist/infra/isInfraWorkloadHealth.d.ts.map +1 -0
- package/dist/infra/isInfraWorkloadHealth.js +37 -0
- package/dist/infra/isInfraWorkloadHealth.js.map +1 -0
- package/dist/infra/isInfraWorkloadSpec.d.ts +4 -0
- package/dist/infra/isInfraWorkloadSpec.d.ts.map +1 -0
- package/dist/infra/isInfraWorkloadSpec.js +70 -0
- package/dist/infra/isInfraWorkloadSpec.js.map +1 -0
- package/dist/infra/isInfraWorkloadValue.d.ts +3 -0
- package/dist/infra/isInfraWorkloadValue.d.ts.map +1 -0
- package/dist/infra/isInfraWorkloadValue.js +40 -0
- package/dist/infra/isInfraWorkloadValue.js.map +1 -0
- package/dist/infra/parseInfraManifest.d.ts +5 -0
- package/dist/infra/parseInfraManifest.d.ts.map +1 -0
- package/dist/infra/parseInfraManifest.js +17 -0
- package/dist/infra/parseInfraManifest.js.map +1 -0
- package/dist/infra/validateInfraAdapterSelection.d.ts +6 -0
- package/dist/infra/validateInfraAdapterSelection.d.ts.map +1 -0
- package/dist/infra/validateInfraAdapterSelection.js +36 -0
- package/dist/infra/validateInfraAdapterSelection.js.map +1 -0
- package/dist/infra.d.ts +16 -0
- package/dist/infra.d.ts.map +1 -0
- package/dist/infra.js +11 -0
- package/dist/infra.js.map +1 -0
- package/dist/media.d.ts +7 -6
- package/dist/media.d.ts.map +1 -1
- package/dist/media.js +5 -5
- package/dist/media.js.map +1 -1
- package/dist/state.d.ts +5 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js.map +1 -1
- package/dist/types/appManifest.d.ts +9 -0
- package/dist/types/appManifest.d.ts.map +1 -0
- package/dist/types/appManifest.js +2 -0
- package/dist/types/appManifest.js.map +1 -0
- package/dist/types/infraAdapters.d.ts +85 -0
- package/dist/types/infraAdapters.d.ts.map +1 -0
- package/dist/types/infraAdapters.js +2 -0
- package/dist/types/infraAdapters.js.map +1 -0
- package/dist/types/infraLifecycle.d.ts +107 -0
- package/dist/types/infraLifecycle.d.ts.map +1 -0
- package/dist/types/infraLifecycle.js +2 -0
- package/dist/types/infraLifecycle.js.map +1 -0
- package/dist/types/infraManifest.d.ts +142 -0
- package/dist/types/infraManifest.d.ts.map +1 -0
- package/dist/types/infraManifest.js +2 -0
- package/dist/types/infraManifest.js.map +1 -0
- package/dist/types/infraSecrets.d.ts +15 -0
- package/dist/types/infraSecrets.d.ts.map +1 -0
- package/dist/types/infraSecrets.js +2 -0
- package/dist/types/infraSecrets.js.map +1 -0
- package/dist/types/infraValidation.d.ts +5 -0
- package/dist/types/infraValidation.d.ts.map +1 -0
- package/dist/types/infraValidation.js +2 -0
- package/dist/types/infraValidation.js.map +1 -0
- package/dist/types/infraWorkload.d.ts +70 -0
- package/dist/types/infraWorkload.d.ts.map +1 -0
- package/dist/types/infraWorkload.js +2 -0
- package/dist/types/infraWorkload.js.map +1 -0
- package/dist/types.d.ts +7 -70
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -9
- package/dist/types.js.map +1 -1
- package/package.json +11 -2
- package/src/appManifest/apis.ts +18 -16
- package/src/appManifest/bindings.ts +18 -1
- package/src/appManifest/constants.ts +19 -0
- package/src/appManifest/data.ts +23 -9
- package/src/appManifest/dataSources.ts +8 -7
- package/src/appManifest/deploy.ts +17 -15
- package/src/appManifest/icon.ts +3 -1
- package/src/appManifest/isAppManifest.ts +95 -0
- package/src/appManifest/isAppStateSpec.ts +13 -0
- package/src/appManifest/isManifestValue.ts +19 -0
- package/src/appManifest/media.ts +11 -10
- package/src/appManifest/navigator.ts +7 -6
- package/src/appManifest/navigatorOptions.ts +9 -16
- package/src/appManifest/parseAppManifest.ts +15 -0
- package/src/appManifest/screens.ts +14 -2
- package/src/appManifest.test.ts +9 -5
- package/src/appManifest.ts +3 -107
- package/src/auth-flow-contract.test.ts +6 -10
- package/src/auth-oauth.test.ts +2 -2
- package/src/auth.ts +3 -2
- package/src/bindings.test.ts +5 -0
- package/src/contracts.test.ts +21 -19
- package/src/deploy.test.ts +13 -5
- package/src/deploy.ts +0 -11
- package/src/environments.ts +4 -0
- package/src/index.ts +2 -1
- package/src/infra/constants.ts +91 -0
- package/src/infra/infraFields.ts +20 -0
- package/src/infra/isInfraAdapterDescriptor.ts +37 -0
- package/src/infra/isInfraAuthSpec.ts +98 -0
- package/src/infra/isInfraCredentialRef.ts +11 -0
- package/src/infra/isInfraDeploymentSpec.ts +75 -0
- package/src/infra/isInfraEnvironmentSpec.ts +95 -0
- package/src/infra/isInfraManifest.ts +29 -0
- package/src/infra/isInfraShape.ts +16 -0
- package/src/infra/isInfraWorkloadHealth.ts +38 -0
- package/src/infra/isInfraWorkloadSpec.ts +87 -0
- package/src/infra/isInfraWorkloadValue.ts +41 -0
- package/src/infra/parseInfraManifest.ts +20 -0
- package/src/infra/validateInfraAdapterSelection.ts +42 -0
- package/src/infra-types.test.ts +78 -0
- package/src/infra-workload.test.ts +186 -0
- package/src/infra.test.ts +268 -0
- package/src/infra.ts +15 -0
- package/src/media.ts +12 -11
- package/src/profile-contract.test.ts +2 -3
- package/src/secrets.test.ts +19 -13
- package/src/state.ts +6 -0
- package/src/types/appManifest.ts +5 -0
- package/src/types/infraAdapters.ts +148 -0
- package/src/types/infraLifecycle.ts +105 -0
- package/src/types/infraManifest.ts +130 -0
- package/src/types/infraSecrets.ts +16 -0
- package/src/types/infraValidation.ts +2 -0
- package/src/types/infraWorkload.ts +64 -0
- package/src/types.ts +7 -87
- package/dist/appManifest/infra.d.ts +0 -2
- package/dist/appManifest/infra.d.ts.map +0 -1
- package/dist/appManifest/infra.js +0 -130
- package/dist/appManifest/infra.js.map +0 -1
- package/dist/appManifest/shared.d.ts +0 -8
- package/dist/appManifest/shared.d.ts.map +0 -1
- package/dist/appManifest/shared.js +0 -31
- package/dist/appManifest/shared.js.map +0 -1
- package/dist/secretManifest.d.ts +0 -11
- package/dist/secretManifest.d.ts.map +0 -1
- package/dist/secretManifest.js +0 -2
- package/dist/secretManifest.js.map +0 -1
- package/src/appManifest/infra.ts +0 -190
- package/src/appManifest/shared.ts +0 -40
- package/src/secretManifest.ts +0 -12
package/src/media.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { isRecord } from '@ankhorage/utility/object';
|
|
2
|
+
import { isNonEmptyString } from '@ankhorage/utility/string';
|
|
3
|
+
|
|
1
4
|
export const MEDIA_ASSET_KINDS = ['image', 'audio', 'video', 'font', 'file'] as const;
|
|
2
5
|
|
|
3
6
|
export type MediaAssetKind = (typeof MEDIA_ASSET_KINDS)[number];
|
|
4
7
|
|
|
5
8
|
export interface MediaStorageSource {
|
|
6
9
|
readonly kind: 'storage';
|
|
7
|
-
|
|
10
|
+
/*** Optional logical storage connection identifier for future multi-storage apps. */
|
|
8
11
|
readonly storageId?: string;
|
|
9
12
|
readonly bucket: string;
|
|
10
13
|
readonly path: string;
|
|
@@ -12,13 +15,13 @@ export interface MediaStorageSource {
|
|
|
12
15
|
|
|
13
16
|
export interface MediaUrlSource {
|
|
14
17
|
readonly kind: 'url';
|
|
15
|
-
|
|
18
|
+
/*** Stable remote URL. Transient/local URL schemes are not canonical media sources. */
|
|
16
19
|
readonly url: string;
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
export interface MediaBundledSource {
|
|
20
23
|
readonly kind: 'bundled';
|
|
21
|
-
|
|
24
|
+
/*** App-relative bundled asset path resolved by the generated/runtime host. */
|
|
22
25
|
readonly path: string;
|
|
23
26
|
}
|
|
24
27
|
|
|
@@ -33,7 +36,7 @@ export interface MediaAssetMetadata {
|
|
|
33
36
|
readonly durationMs?: number;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
|
|
39
|
+
/*** Canonical Studio-managed authoring media entry. */
|
|
37
40
|
export interface MediaAsset {
|
|
38
41
|
readonly id: string;
|
|
39
42
|
readonly name: string;
|
|
@@ -45,24 +48,22 @@ export interface MediaAsset {
|
|
|
45
48
|
|
|
46
49
|
export type MediaAssetRegistry = Readonly<Record<string, MediaAsset>>;
|
|
47
50
|
|
|
48
|
-
|
|
51
|
+
/*** App-authoring media pool. Runtime/user-generated uploads do not belong here. */
|
|
49
52
|
export interface MediaManifest {
|
|
50
53
|
readonly assets: MediaAssetRegistry;
|
|
51
54
|
}
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
/*** Stable component/property reference to one entry in `AppManifest.media.assets`. */
|
|
54
57
|
export interface MediaAssetReference {
|
|
55
58
|
readonly mediaId: string;
|
|
56
59
|
}
|
|
57
60
|
|
|
61
|
+
/*** Validate an authored media reference with exactly one enumerable key and a non-empty media ID. */
|
|
58
62
|
export function isMediaAssetReference(value: unknown): value is MediaAssetReference {
|
|
59
63
|
return (
|
|
60
|
-
|
|
61
|
-
value !== null &&
|
|
62
|
-
!Array.isArray(value) &&
|
|
64
|
+
isRecord(value) &&
|
|
63
65
|
Object.keys(value).length === 1 &&
|
|
64
66
|
'mediaId' in value &&
|
|
65
|
-
|
|
66
|
-
value.mediaId.trim().length > 0
|
|
67
|
+
isNonEmptyString(value.mediaId)
|
|
67
68
|
);
|
|
68
69
|
}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
AUTH_PROFILE_CREATE_STRATEGIES,
|
|
5
5
|
AUTH_PROFILE_PRIMARY_KEY_STRATEGIES,
|
|
6
6
|
AUTH_PROFILE_UPDATE_STRATEGIES,
|
|
7
|
-
type
|
|
7
|
+
type InfraAuthSpec,
|
|
8
8
|
} from './index';
|
|
9
9
|
|
|
10
10
|
describe('profile contract', () => {
|
|
@@ -15,10 +15,9 @@ describe('profile contract', () => {
|
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
it('serializes profile settings on an auth spec', () => {
|
|
18
|
-
const auth:
|
|
18
|
+
const auth: InfraAuthSpec = {
|
|
19
19
|
scope: 'global',
|
|
20
20
|
provider: 'supabase',
|
|
21
|
-
authorization: { kind: 'RBAC', engine: 'native' },
|
|
22
21
|
profile: {
|
|
23
22
|
fields: ['email', 'displayName', 'avatarUrl'],
|
|
24
23
|
table: 'profiles',
|
package/src/secrets.test.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import './secretManifest';
|
|
2
|
-
|
|
3
1
|
import { describe, expect, test } from 'bun:test';
|
|
4
2
|
|
|
5
3
|
import type { AuthOAuthProviderConfig } from './auth';
|
|
4
|
+
import type { InfraManifest } from './infra';
|
|
6
5
|
import {
|
|
7
6
|
findForbiddenInlineSecretFields,
|
|
8
7
|
normalizeSecretRef,
|
|
9
8
|
normalizeSecretScope,
|
|
10
9
|
validateSecretPayload,
|
|
11
10
|
} from './secrets';
|
|
12
|
-
import type { InfraManifest } from './types';
|
|
13
11
|
|
|
14
12
|
describe('secret-store contracts', () => {
|
|
15
13
|
test('normalizes logical secret references', () => {
|
|
@@ -70,19 +68,27 @@ describe('secret-store contracts', () => {
|
|
|
70
68
|
|
|
71
69
|
const infra: InfraManifest = {
|
|
72
70
|
modules: [],
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
environments: {
|
|
72
|
+
local: {
|
|
73
|
+
deployment: { compute: { provider: 'local' }, runtime: { provider: 'minikube' } },
|
|
74
|
+
database: { provider: 'supabase' },
|
|
75
|
+
secretStore: { provider: 'supabase-vault' },
|
|
76
|
+
auth: {
|
|
77
|
+
scope: 'global',
|
|
78
|
+
provider: 'supabase',
|
|
79
|
+
oauth: {
|
|
80
|
+
enabled: true,
|
|
81
|
+
callbackRoute: '/auth/callback',
|
|
82
|
+
providers: [provider],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
81
85
|
},
|
|
82
86
|
},
|
|
83
87
|
};
|
|
84
88
|
|
|
85
|
-
expect(infra.secretStore?.provider).toBe('supabase-vault');
|
|
86
|
-
expect(infra.auth?.oauth?.providers[0]?.credentialsRef).toBe(
|
|
89
|
+
expect(infra.environments.local.secretStore?.provider).toBe('supabase-vault');
|
|
90
|
+
expect(infra.environments.local.auth?.oauth?.providers[0]?.credentialsRef).toBe(
|
|
91
|
+
'auth/oauth/google',
|
|
92
|
+
);
|
|
87
93
|
});
|
|
88
94
|
});
|
package/src/state.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/** Legend currently implements in-memory state only; unsupported persistence cannot be selected. */
|
|
2
|
+
export interface AppStateSpec {
|
|
3
|
+
readonly provider: 'legend';
|
|
4
|
+
readonly persistence?: false;
|
|
5
|
+
}
|
|
6
|
+
|
|
1
7
|
export type StatePrimitive = string | number | boolean | null;
|
|
2
8
|
|
|
3
9
|
export type StateValue =
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { AppEnvironmentId } from '../environments';
|
|
2
|
+
import type { INFRA_ADAPTER_CATALOG } from '../infra/constants';
|
|
3
|
+
import type {
|
|
4
|
+
InfraDestroyRequest,
|
|
5
|
+
InfraGeneratedArtifact,
|
|
6
|
+
InfraLedger,
|
|
7
|
+
InfraOutput,
|
|
8
|
+
InfraOwnedResource,
|
|
9
|
+
InfraPlanAction,
|
|
10
|
+
InfraResourceStatus,
|
|
11
|
+
InfraResult,
|
|
12
|
+
} from './infraLifecycle';
|
|
13
|
+
import type {
|
|
14
|
+
InfraAdapterId,
|
|
15
|
+
InfraComputeProviderId,
|
|
16
|
+
InfraComputeSelection,
|
|
17
|
+
InfraEnvironmentSpec,
|
|
18
|
+
InfraRuntimeProviderId,
|
|
19
|
+
InfraRuntimeSelection,
|
|
20
|
+
} from './infraManifest';
|
|
21
|
+
import type { InfraControlPlaneCredentialRef, InfraSecretReference } from './infraSecrets';
|
|
22
|
+
import type { InfraWorkloadSpec } from './infraWorkload';
|
|
23
|
+
|
|
24
|
+
/** Package exports must match this exact catalog entry; optional operations are advertised explicitly. */
|
|
25
|
+
export type InfraAdapterDescriptor<P extends InfraAdapterId = InfraAdapterId> = {
|
|
26
|
+
[K in P]: (typeof INFRA_ADAPTER_CATALOG)[K] & {
|
|
27
|
+
readonly operations?: readonly ('suspend' | 'resume' | 'generate' | 'diagnostics')[];
|
|
28
|
+
};
|
|
29
|
+
}[P];
|
|
30
|
+
|
|
31
|
+
export type InfraComputeTarget = {
|
|
32
|
+
readonly id: string;
|
|
33
|
+
readonly os: 'linux' | 'darwin' | 'windows';
|
|
34
|
+
readonly architecture: 'amd64' | 'arm64';
|
|
35
|
+
} & (
|
|
36
|
+
| { readonly kind: 'local-host' }
|
|
37
|
+
| {
|
|
38
|
+
readonly kind: 'ssh-host';
|
|
39
|
+
readonly host: string;
|
|
40
|
+
readonly port: number;
|
|
41
|
+
readonly user: string;
|
|
42
|
+
readonly credential: InfraControlPlaneCredentialRef;
|
|
43
|
+
/** Expected host key supplied by the compute owner; runtimes must verify host authenticity. */
|
|
44
|
+
readonly hostKeyFingerprint: string;
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
/** Trusted execution-only ports. Implementations must not serialize resolved credential values. */
|
|
49
|
+
export interface InfraExecutionContext {
|
|
50
|
+
readonly projectId: string;
|
|
51
|
+
readonly environment: AppEnvironmentId;
|
|
52
|
+
readonly desired: InfraEnvironmentSpec;
|
|
53
|
+
readonly previous?: InfraLedger;
|
|
54
|
+
readonly signal?: AbortSignal;
|
|
55
|
+
readonly credentials: {
|
|
56
|
+
resolveAsync(
|
|
57
|
+
reference: InfraControlPlaneCredentialRef,
|
|
58
|
+
): Promise<InfraResult<Readonly<Record<string, string>>>>;
|
|
59
|
+
};
|
|
60
|
+
readonly secrets: {
|
|
61
|
+
resolveAsync(reference: InfraSecretReference): Promise<InfraResult<string>>;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface InfraReconcileResult {
|
|
66
|
+
readonly resources: readonly InfraOwnedResource[];
|
|
67
|
+
readonly outputs: readonly InfraOutput[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface InfraComputeAdapter<P extends InfraComputeProviderId = InfraComputeProviderId> {
|
|
71
|
+
readonly descriptor: InfraAdapterDescriptor<P>;
|
|
72
|
+
/** Read-only prerequisites, config and control-plane credential validation. */
|
|
73
|
+
validateAsync(
|
|
74
|
+
context: InfraExecutionContext,
|
|
75
|
+
selection: InfraComputeSelection<P>,
|
|
76
|
+
): Promise<InfraResult<null>>;
|
|
77
|
+
planAsync(
|
|
78
|
+
context: InfraExecutionContext,
|
|
79
|
+
selection: InfraComputeSelection<P>,
|
|
80
|
+
): Promise<InfraResult<readonly InfraPlanAction[]>>;
|
|
81
|
+
ensureAsync(
|
|
82
|
+
context: InfraExecutionContext,
|
|
83
|
+
selection: InfraComputeSelection<P>,
|
|
84
|
+
): Promise<
|
|
85
|
+
InfraResult<InfraReconcileResult & { readonly targets: readonly InfraComputeTarget[] }>
|
|
86
|
+
>;
|
|
87
|
+
statusAsync(context: InfraExecutionContext): Promise<InfraResult<readonly InfraResourceStatus[]>>;
|
|
88
|
+
destroyAsync(
|
|
89
|
+
context: InfraExecutionContext,
|
|
90
|
+
request: InfraDestroyRequest,
|
|
91
|
+
): Promise<InfraResult<InfraReconcileResult>>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface InfraRuntimeDesiredState<
|
|
95
|
+
P extends InfraRuntimeProviderId = InfraRuntimeProviderId,
|
|
96
|
+
> {
|
|
97
|
+
readonly selection: InfraRuntimeSelection<P>;
|
|
98
|
+
readonly targets: readonly InfraComputeTarget[];
|
|
99
|
+
readonly workloads: readonly InfraWorkloadSpec[];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface InfraRuntimeAdapter<P extends InfraRuntimeProviderId = InfraRuntimeProviderId> {
|
|
103
|
+
readonly descriptor: InfraAdapterDescriptor<P>;
|
|
104
|
+
/** Read-only prerequisites and desired-state validation; no cluster creation. */
|
|
105
|
+
validateAsync(
|
|
106
|
+
context: InfraExecutionContext,
|
|
107
|
+
desired: InfraRuntimeDesiredState<P>,
|
|
108
|
+
): Promise<InfraResult<null>>;
|
|
109
|
+
planAsync(
|
|
110
|
+
context: InfraExecutionContext,
|
|
111
|
+
desired: InfraRuntimeDesiredState<P>,
|
|
112
|
+
): Promise<InfraResult<readonly InfraPlanAction[]>>;
|
|
113
|
+
ensureAsync(
|
|
114
|
+
context: InfraExecutionContext,
|
|
115
|
+
desired: InfraRuntimeDesiredState<P>,
|
|
116
|
+
): Promise<InfraResult<InfraReconcileResult>>;
|
|
117
|
+
statusAsync(context: InfraExecutionContext): Promise<InfraResult<readonly InfraResourceStatus[]>>;
|
|
118
|
+
suspendAsync(context: InfraExecutionContext): Promise<InfraResult<InfraReconcileResult>>;
|
|
119
|
+
destroyAsync(
|
|
120
|
+
context: InfraExecutionContext,
|
|
121
|
+
request: InfraDestroyRequest,
|
|
122
|
+
): Promise<InfraResult<InfraReconcileResult>>;
|
|
123
|
+
generateAsync?(
|
|
124
|
+
context: InfraExecutionContext,
|
|
125
|
+
desired: InfraRuntimeDesiredState<P>,
|
|
126
|
+
): Promise<InfraResult<readonly InfraGeneratedArtifact[]>>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** A service can own several capabilities but contributes one deduplicated platform instance. */
|
|
130
|
+
export interface InfraServiceAdapter {
|
|
131
|
+
readonly descriptor: InfraAdapterDescriptor<'supabase' | 'cerbos' | 'r2' | 'supabase-vault'>;
|
|
132
|
+
/** Read-only service config, bootstrap credentials and dependency validation. */
|
|
133
|
+
validateAsync(context: InfraExecutionContext): Promise<InfraResult<null>>;
|
|
134
|
+
planAsync(context: InfraExecutionContext): Promise<InfraResult<readonly InfraPlanAction[]>>;
|
|
135
|
+
desiredWorkloadsAsync(
|
|
136
|
+
context: InfraExecutionContext,
|
|
137
|
+
): Promise<InfraResult<readonly InfraWorkloadSpec[]>>;
|
|
138
|
+
reconcileAsync(
|
|
139
|
+
context: InfraExecutionContext,
|
|
140
|
+
runtimeOutputs: readonly InfraOutput[],
|
|
141
|
+
): Promise<InfraResult<InfraReconcileResult>>;
|
|
142
|
+
statusAsync(context: InfraExecutionContext): Promise<InfraResult<readonly InfraResourceStatus[]>>;
|
|
143
|
+
destroyAsync(
|
|
144
|
+
context: InfraExecutionContext,
|
|
145
|
+
request: InfraDestroyRequest,
|
|
146
|
+
): Promise<InfraResult<InfraReconcileResult>>;
|
|
147
|
+
suspendAsync?(context: InfraExecutionContext): Promise<InfraResult<InfraReconcileResult>>;
|
|
148
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { AppEnvironmentId } from '../environments';
|
|
2
|
+
import type { InfraAdapterId } from './infraManifest';
|
|
3
|
+
import type { InfraSecretReference } from './infraSecrets';
|
|
4
|
+
|
|
5
|
+
/** Identity must be verified before mutation; unowned resources must never be pruned. */
|
|
6
|
+
export interface InfraResourceIdentity {
|
|
7
|
+
readonly projectId: string;
|
|
8
|
+
readonly environment: AppEnvironmentId;
|
|
9
|
+
readonly adapter: InfraAdapterId;
|
|
10
|
+
readonly resourceId: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface InfraOwnedResource {
|
|
14
|
+
readonly identity: InfraResourceIdentity;
|
|
15
|
+
readonly externalId?: string;
|
|
16
|
+
readonly persistent: boolean;
|
|
17
|
+
readonly retention: 'retain' | 'delete-on-destroy';
|
|
18
|
+
readonly dependsOn: readonly InfraResourceIdentity[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface InfraDiagnostic {
|
|
22
|
+
readonly severity: 'info' | 'warning' | 'error';
|
|
23
|
+
readonly code: string;
|
|
24
|
+
/** Safe human-readable detail. Tokens and privileged values must be redacted by the producer. */
|
|
25
|
+
readonly message: string;
|
|
26
|
+
readonly path?: readonly (string | number)[];
|
|
27
|
+
readonly owner?: InfraResourceIdentity;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type InfraResult<T> =
|
|
31
|
+
| { readonly ok: true; readonly value: T; readonly diagnostics: readonly InfraDiagnostic[] }
|
|
32
|
+
| { readonly ok: false; readonly diagnostics: readonly InfraDiagnostic[] };
|
|
33
|
+
|
|
34
|
+
export interface InfraPlanAction {
|
|
35
|
+
readonly owner: InfraResourceIdentity;
|
|
36
|
+
readonly operation: 'create' | 'update' | 'delete' | 'retain' | 'noop';
|
|
37
|
+
readonly impact: 'none' | 'interrupts-service' | 'deletes-data';
|
|
38
|
+
readonly detail: string;
|
|
39
|
+
readonly dependsOn: readonly InfraResourceIdentity[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface InfraPlan {
|
|
43
|
+
readonly projectId: string;
|
|
44
|
+
readonly environment: AppEnvironmentId;
|
|
45
|
+
/** Ordered dependency-first; teardown consumers reverse dependency order. */
|
|
46
|
+
readonly actions: readonly InfraPlanAction[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface InfraResourceStatus {
|
|
50
|
+
readonly owner: InfraResourceIdentity;
|
|
51
|
+
readonly state:
|
|
52
|
+
'absent' | 'pending' | 'ready' | 'degraded' | 'stopped' | 'retained' | 'failed' | 'unknown';
|
|
53
|
+
readonly detail?: string;
|
|
54
|
+
readonly diagnostics?: readonly InfraDiagnostic[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface InfraStatus {
|
|
58
|
+
readonly projectId: string;
|
|
59
|
+
readonly environment: AppEnvironmentId;
|
|
60
|
+
readonly state: InfraResourceStatus['state'];
|
|
61
|
+
readonly resources: readonly InfraResourceStatus[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** A privileged output has a reference, never a value field or environment export name. */
|
|
65
|
+
export type InfraOutput = { readonly owner: InfraResourceIdentity; readonly name: string } & (
|
|
66
|
+
| {
|
|
67
|
+
readonly visibility: 'public';
|
|
68
|
+
readonly value: string | number | boolean;
|
|
69
|
+
readonly environmentVariable?: string;
|
|
70
|
+
readonly reference?: never;
|
|
71
|
+
}
|
|
72
|
+
| {
|
|
73
|
+
readonly visibility: 'secret';
|
|
74
|
+
readonly reference: InfraSecretReference;
|
|
75
|
+
readonly value?: never;
|
|
76
|
+
readonly environmentVariable?: never;
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
export interface InfraGeneratedArtifact {
|
|
81
|
+
readonly owner: InfraResourceIdentity;
|
|
82
|
+
/** Project-relative file path validated by the writer before touching the filesystem. */
|
|
83
|
+
readonly path: string;
|
|
84
|
+
readonly content: string;
|
|
85
|
+
readonly executable?: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface InfraLedger {
|
|
89
|
+
readonly schemaVersion: 1;
|
|
90
|
+
readonly projectId: string;
|
|
91
|
+
readonly environment: AppEnvironmentId;
|
|
92
|
+
readonly resources: readonly InfraOwnedResource[];
|
|
93
|
+
readonly artifacts: readonly { readonly owner: InfraResourceIdentity; readonly path: string }[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** No default environment or confirmation is possible for destruction. */
|
|
97
|
+
export interface InfraDestroyRequest {
|
|
98
|
+
readonly projectId: string;
|
|
99
|
+
readonly environment: AppEnvironmentId;
|
|
100
|
+
readonly confirmation: { readonly projectId: string; readonly environment: AppEnvironmentId };
|
|
101
|
+
/** Data deletion is a separate, explicit resource-scoped authorization in every environment. */
|
|
102
|
+
readonly persistence:
|
|
103
|
+
| { readonly policy: 'retain' }
|
|
104
|
+
| { readonly policy: 'delete'; readonly confirmedResources: readonly InfraResourceIdentity[] };
|
|
105
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { AuthFlowConfig, AuthOAuthConfig } from '../auth';
|
|
2
|
+
import type { ApiDefinitionList } from '../data';
|
|
3
|
+
import type { AppEnvironmentId } from '../environments';
|
|
4
|
+
import type { INFRA_ADAPTER_CATALOG, INFRA_RUNTIME_COMPATIBILITY } from '../infra/constants';
|
|
5
|
+
import type { AuthProfileSpec, AuthScope, AuthSignInSpec, AuthSignUpSpec } from '../types';
|
|
6
|
+
import type { InfraControlPlaneCredentialRef } from './infraSecrets';
|
|
7
|
+
import type { InfraWorkloadSpec } from './infraWorkload';
|
|
8
|
+
|
|
9
|
+
export type InfraAdapterId = keyof typeof INFRA_ADAPTER_CATALOG;
|
|
10
|
+
export type InfraCapability =
|
|
11
|
+
(typeof INFRA_ADAPTER_CATALOG)[InfraAdapterId]['capabilities'][number];
|
|
12
|
+
export type InfraProviderFor<C extends InfraCapability> = {
|
|
13
|
+
[P in InfraAdapterId]: C extends (typeof INFRA_ADAPTER_CATALOG)[P]['capabilities'][number]
|
|
14
|
+
? P
|
|
15
|
+
: never;
|
|
16
|
+
}[InfraAdapterId];
|
|
17
|
+
export type InfraComputeProviderId = InfraProviderFor<'compute'>;
|
|
18
|
+
export type InfraRuntimeProviderId = keyof typeof INFRA_RUNTIME_COMPATIBILITY;
|
|
19
|
+
|
|
20
|
+
/** Non-secret provider configuration; credentials are resolved only at the execution boundary. */
|
|
21
|
+
export interface InfraComputeConfigMap {
|
|
22
|
+
readonly local: { readonly workingDirectory?: string };
|
|
23
|
+
readonly hetzner: {
|
|
24
|
+
readonly location: string;
|
|
25
|
+
readonly serverType?: string;
|
|
26
|
+
readonly image?: string;
|
|
27
|
+
readonly credentials?: InfraControlPlaneCredentialRef;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface InfraRuntimeConfigMap {
|
|
32
|
+
readonly minikube: {
|
|
33
|
+
readonly profile?: string;
|
|
34
|
+
readonly driver?: 'docker' | 'podman';
|
|
35
|
+
readonly cpus?: number;
|
|
36
|
+
readonly memoryMiB?: number;
|
|
37
|
+
};
|
|
38
|
+
readonly k3s: {
|
|
39
|
+
readonly version?: string;
|
|
40
|
+
readonly topology?: { readonly servers: number; readonly agents: number };
|
|
41
|
+
};
|
|
42
|
+
readonly 'docker-compose': { readonly projectName?: string };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type InfraComputeSelection<P extends InfraComputeProviderId = InfraComputeProviderId> = {
|
|
46
|
+
[K in P]: { readonly provider: K } & InfraComputeConfigMap[K];
|
|
47
|
+
}[P];
|
|
48
|
+
export type InfraRuntimeSelection<P extends InfraRuntimeProviderId = InfraRuntimeProviderId> = {
|
|
49
|
+
[K in P]: { readonly provider: K } & InfraRuntimeConfigMap[K];
|
|
50
|
+
}[P];
|
|
51
|
+
|
|
52
|
+
/** A discriminated union derived from the runtime catalog, never a Cartesian product. */
|
|
53
|
+
export type InfraDeploymentSpec = {
|
|
54
|
+
[R in InfraRuntimeProviderId]: {
|
|
55
|
+
readonly compute: InfraComputeSelection<(typeof INFRA_RUNTIME_COMPATIBILITY)[R][number]>;
|
|
56
|
+
readonly runtime: InfraRuntimeSelection<R>;
|
|
57
|
+
};
|
|
58
|
+
}[InfraRuntimeProviderId];
|
|
59
|
+
|
|
60
|
+
export interface InfraDatabaseConfigMap {
|
|
61
|
+
readonly supabase: { readonly tier?: 'dev' | 'prod' };
|
|
62
|
+
}
|
|
63
|
+
export interface InfraObjectStorageConfigMap {
|
|
64
|
+
readonly supabase: { readonly buckets?: readonly string[] };
|
|
65
|
+
readonly r2: {
|
|
66
|
+
readonly buckets?: readonly string[];
|
|
67
|
+
readonly accountId?: string;
|
|
68
|
+
readonly credentials?: InfraControlPlaneCredentialRef;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export interface InfraAuthConfigMap {
|
|
72
|
+
readonly supabase: {
|
|
73
|
+
readonly scope?: AuthScope;
|
|
74
|
+
readonly flow?: AuthFlowConfig;
|
|
75
|
+
readonly signIn?: AuthSignInSpec;
|
|
76
|
+
readonly signUp?: AuthSignUpSpec;
|
|
77
|
+
readonly oauth?: AuthOAuthConfig;
|
|
78
|
+
readonly profile?: AuthProfileSpec;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export interface InfraAuthzConfigMap {
|
|
82
|
+
readonly cerbos: { readonly kind: 'RBAC' | 'ABAC' };
|
|
83
|
+
}
|
|
84
|
+
export interface InfraSecretStoreConfigMap {
|
|
85
|
+
readonly 'supabase-vault': { readonly schema?: string };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type InfraDatabaseSpec = {
|
|
89
|
+
[P in InfraProviderFor<'database'>]: { readonly provider: P } & InfraDatabaseConfigMap[P];
|
|
90
|
+
}[InfraProviderFor<'database'>];
|
|
91
|
+
export type InfraObjectStorageSpec = {
|
|
92
|
+
[P in InfraProviderFor<'objectStorage'>]: {
|
|
93
|
+
readonly provider: P;
|
|
94
|
+
} & InfraObjectStorageConfigMap[P];
|
|
95
|
+
}[InfraProviderFor<'objectStorage'>];
|
|
96
|
+
export type InfraAuthSpec = {
|
|
97
|
+
[P in InfraProviderFor<'auth'>]: { readonly provider: P } & InfraAuthConfigMap[P];
|
|
98
|
+
}[InfraProviderFor<'auth'>];
|
|
99
|
+
export type InfraAuthzSpec = {
|
|
100
|
+
[P in InfraProviderFor<'authz'>]: { readonly provider: P } & InfraAuthzConfigMap[P];
|
|
101
|
+
}[InfraProviderFor<'authz'>];
|
|
102
|
+
export type InfraSecretStoreSpec = {
|
|
103
|
+
[P in InfraProviderFor<'secretStore'>]: { readonly provider: P } & InfraSecretStoreConfigMap[P];
|
|
104
|
+
}[InfraProviderFor<'secretStore'>];
|
|
105
|
+
|
|
106
|
+
export interface InfraNetworkingSpec {
|
|
107
|
+
/** Public DNS name intent, not automatic DNS/CDN vendor provisioning. */
|
|
108
|
+
readonly domain?: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface InfraEnvironmentSpec {
|
|
112
|
+
readonly deployment: InfraDeploymentSpec;
|
|
113
|
+
readonly database?: InfraDatabaseSpec;
|
|
114
|
+
readonly objectStorage?: InfraObjectStorageSpec;
|
|
115
|
+
readonly auth?: InfraAuthSpec;
|
|
116
|
+
readonly authz?: InfraAuthzSpec;
|
|
117
|
+
readonly secretStore?: InfraSecretStoreSpec;
|
|
118
|
+
readonly networking?: InfraNetworkingSpec;
|
|
119
|
+
readonly workloads?: readonly InfraWorkloadSpec[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface InfraManifest {
|
|
123
|
+
readonly environments: Readonly<
|
|
124
|
+
Record<'local', InfraEnvironmentSpec> &
|
|
125
|
+
Partial<Record<Exclude<AppEnvironmentId, 'local'>, InfraEnvironmentSpec>>
|
|
126
|
+
>;
|
|
127
|
+
readonly apis?: ApiDefinitionList;
|
|
128
|
+
readonly modules: readonly string[];
|
|
129
|
+
readonly modulesConfig?: Readonly<Record<string, unknown>>;
|
|
130
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AppEnvironmentId } from '../environments';
|
|
2
|
+
|
|
3
|
+
/** Bootstrap credentials cannot depend on the managed secret store being provisioned. */
|
|
4
|
+
export interface InfraControlPlaneCredentialRef {
|
|
5
|
+
readonly source: 'control-plane';
|
|
6
|
+
readonly name: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Privileged values are never serialized into manifests, ledgers or normal outputs. */
|
|
10
|
+
export interface InfraSecretReference {
|
|
11
|
+
readonly source: 'secret-store';
|
|
12
|
+
readonly projectId: string;
|
|
13
|
+
readonly environment: AppEnvironmentId;
|
|
14
|
+
readonly ref: string;
|
|
15
|
+
readonly key: string;
|
|
16
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { InfraSecretReference } from './infraSecrets';
|
|
2
|
+
|
|
3
|
+
export interface InfraWorkloadArtifact {
|
|
4
|
+
readonly kind: 'image';
|
|
5
|
+
/** Prebuilt image, optionally pinned by digest. No registry/build provider requirement. */
|
|
6
|
+
readonly image: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type InfraWorkloadValue =
|
|
10
|
+
| { readonly kind: 'literal'; readonly value: string }
|
|
11
|
+
| { readonly kind: 'secret'; readonly reference: InfraSecretReference }
|
|
12
|
+
| { readonly kind: 'output'; readonly resourceId: string; readonly output: string };
|
|
13
|
+
|
|
14
|
+
export interface InfraWorkloadPort {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly port: number;
|
|
17
|
+
readonly protocol?: 'tcp' | 'udp';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type InfraWorkloadHealthSpec = {
|
|
21
|
+
readonly intervalSeconds?: number;
|
|
22
|
+
readonly timeoutSeconds?: number;
|
|
23
|
+
readonly failureThreshold?: number;
|
|
24
|
+
} & (
|
|
25
|
+
| { readonly kind: 'http'; readonly port: number; readonly path: string }
|
|
26
|
+
| { readonly kind: 'tcp'; readonly port: number }
|
|
27
|
+
| { readonly kind: 'command'; readonly command: readonly string[] }
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export interface InfraWorkloadResourceSpec {
|
|
31
|
+
readonly cpuMillis?: number;
|
|
32
|
+
readonly memoryMiB?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface InfraWorkloadVolumeSpec {
|
|
36
|
+
readonly id: string;
|
|
37
|
+
readonly mountPath: string;
|
|
38
|
+
readonly sizeGiB: number;
|
|
39
|
+
/** Persistence survives down and is retained by default on destroy. */
|
|
40
|
+
readonly retention: 'retain' | 'delete-on-destroy';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Portable config/policy files; secret values are materialized by the runtime. */
|
|
44
|
+
export interface InfraWorkloadFileSpec {
|
|
45
|
+
readonly path: string;
|
|
46
|
+
readonly content: InfraWorkloadValue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface InfraWorkloadSpec {
|
|
50
|
+
readonly id: string;
|
|
51
|
+
readonly artifact: InfraWorkloadArtifact;
|
|
52
|
+
readonly command?: readonly string[];
|
|
53
|
+
readonly args?: readonly string[];
|
|
54
|
+
readonly ports?: readonly InfraWorkloadPort[];
|
|
55
|
+
readonly environment?: Readonly<Record<string, InfraWorkloadValue>>;
|
|
56
|
+
readonly files?: readonly InfraWorkloadFileSpec[];
|
|
57
|
+
readonly health?: InfraWorkloadHealthSpec;
|
|
58
|
+
readonly resources?: InfraWorkloadResourceSpec;
|
|
59
|
+
readonly persistence?: readonly InfraWorkloadVolumeSpec[];
|
|
60
|
+
readonly exposure?: 'internal' | 'public';
|
|
61
|
+
readonly replicas?: number;
|
|
62
|
+
/** IDs in the composed desired-state graph; the orchestrator validates missing/cyclic edges. */
|
|
63
|
+
readonly dependsOn?: readonly string[];
|
|
64
|
+
}
|