@ankhorage/contracts 21.0.0 → 22.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 +6 -0
- package/dist/appManifest/apis.d.ts +3 -3
- package/dist/appManifest/apis.d.ts.map +1 -1
- package/dist/appManifest/apis.js +4 -6
- package/dist/appManifest/apis.js.map +1 -1
- package/dist/appManifest/bindings.d.ts.map +1 -1
- package/dist/appManifest/bindings.js +2 -1
- package/dist/appManifest/bindings.js.map +1 -1
- package/dist/appManifest/data.d.ts.map +1 -1
- package/dist/appManifest/data.js +5 -4
- package/dist/appManifest/data.js.map +1 -1
- package/dist/appManifest/isAppManifest.js +3 -3
- package/dist/appManifest/isAppManifest.js.map +1 -1
- package/dist/appManifest/isManifestValue.d.ts +1 -1
- package/dist/appManifest/isManifestValue.d.ts.map +1 -1
- package/dist/appManifest/isManifestValue.js +3 -12
- package/dist/appManifest/isManifestValue.js.map +1 -1
- package/dist/appManifest/screens.d.ts +3 -2
- package/dist/appManifest/screens.d.ts.map +1 -1
- package/dist/appManifest/screens.js +15 -7
- package/dist/appManifest/screens.js.map +1 -1
- package/dist/bindings.d.ts +2 -3
- package/dist/bindings.d.ts.map +1 -1
- package/dist/bindings.js.map +1 -1
- package/dist/collections.d.ts +4 -0
- package/dist/collections.d.ts.map +1 -0
- package/dist/collections.js +6 -0
- package/dist/collections.js.map +1 -0
- package/dist/data/apis.d.ts +1 -1
- package/dist/data/apis.d.ts.map +1 -1
- package/dist/data/apis.js.map +1 -1
- package/dist/data/values.d.ts +2 -3
- package/dist/data/values.d.ts.map +1 -1
- package/dist/data/values.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/infra/isInfraEnvironmentSpec.d.ts.map +1 -1
- package/dist/infra/isInfraEnvironmentSpec.js +10 -12
- package/dist/infra/isInfraEnvironmentSpec.js.map +1 -1
- package/dist/infra/isInfraManifest.d.ts.map +1 -1
- package/dist/infra/isInfraManifest.js +14 -5
- package/dist/infra/isInfraManifest.js.map +1 -1
- package/dist/infra/isInfraWorkloadSpec.d.ts.map +1 -1
- package/dist/infra/isInfraWorkloadSpec.js +26 -20
- package/dist/infra/isInfraWorkloadSpec.js.map +1 -1
- package/dist/requirements.d.ts +5 -10
- package/dist/requirements.d.ts.map +1 -1
- package/dist/requirements.js.map +1 -1
- package/dist/serializable.d.ts +6 -0
- package/dist/serializable.d.ts.map +1 -0
- package/dist/serializable.js +14 -0
- package/dist/serializable.js.map +1 -0
- package/dist/state.d.ts +2 -3
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js.map +1 -1
- package/dist/types/infraManifest.d.ts +14 -13
- package/dist/types/infraManifest.d.ts.map +1 -1
- package/dist/types/infraManifest.js.map +1 -1
- package/dist/types/infraWorkload.d.ts +11 -11
- package/dist/types/infraWorkload.d.ts.map +1 -1
- package/dist/types/infraWorkload.js.map +1 -1
- package/dist/types.d.ts +9 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/appManifest/apis.ts +9 -6
- package/src/appManifest/bindings.ts +7 -1
- package/src/appManifest/data.ts +13 -4
- package/src/appManifest/isAppManifest.ts +3 -3
- package/src/appManifest/isManifestValue.ts +3 -16
- package/src/appManifest/screens.ts +21 -10
- package/src/appManifest.test.ts +21 -16
- package/src/bindings.test.ts +11 -8
- package/src/bindings.ts +2 -9
- package/src/collections.ts +8 -0
- package/src/contracts.test.ts +16 -13
- package/src/data/apis.test.ts +6 -4
- package/src/data/apis.ts +1 -1
- package/src/data/values.ts +3 -9
- package/src/deploy.test.ts +4 -4
- package/src/index.ts +2 -0
- package/src/infra/isInfraEnvironmentSpec.ts +16 -16
- package/src/infra/isInfraManifest.ts +17 -6
- package/src/infra/isInfraWorkloadSpec.ts +39 -24
- package/src/infra-published-port.test.ts +8 -8
- package/src/infra-workload-persistence.test.ts +4 -4
- package/src/infra-workload.test.ts +24 -22
- package/src/infra.test.ts +16 -20
- package/src/infraPersistence.test.ts +1 -1
- package/src/infraServices.test.ts +1 -1
- package/src/requirements.test.ts +2 -2
- package/src/requirements.ts +6 -12
- package/src/secrets.test.ts +1 -1
- package/src/serializable.ts +25 -0
- package/src/state.ts +3 -6
- package/src/types/infraManifest.ts +17 -13
- package/src/types/infraWorkload.ts +12 -11
- package/src/types.ts +11 -12
|
@@ -10,6 +10,13 @@ import {
|
|
|
10
10
|
} from './infra';
|
|
11
11
|
import type { AppManifest } from './types';
|
|
12
12
|
|
|
13
|
+
const defaultTheme = {
|
|
14
|
+
id: 'default',
|
|
15
|
+
name: 'Default',
|
|
16
|
+
light: { primaryColor: '#3366ff', harmony: 'analogous' },
|
|
17
|
+
dark: { primaryColor: '#6699ff', harmony: 'analogous' },
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
13
20
|
const reference = {
|
|
14
21
|
source: 'secret-store',
|
|
15
22
|
projectId: 'example',
|
|
@@ -22,7 +29,7 @@ const workload = {
|
|
|
22
29
|
artifact: { kind: 'image', image: 'example/backend@sha256:abc' },
|
|
23
30
|
command: ['server'],
|
|
24
31
|
args: ['--verbose'],
|
|
25
|
-
ports:
|
|
32
|
+
ports: { http: { port: 8080, publishedPort: 18_080 } },
|
|
26
33
|
environment: {
|
|
27
34
|
NODE_ENV: { kind: 'literal', value: 'production' },
|
|
28
35
|
DB_PASSWORD: { kind: 'secret', reference },
|
|
@@ -45,36 +52,31 @@ const workload = {
|
|
|
45
52
|
],
|
|
46
53
|
},
|
|
47
54
|
},
|
|
48
|
-
files:
|
|
55
|
+
files: { '/etc/backend/config.json': { kind: 'literal', value: '{}' } },
|
|
49
56
|
health: { kind: 'http', port: 8080, path: '/health', intervalSeconds: 5 },
|
|
50
57
|
resources: { cpuMillis: 500, memoryMiB: 256 },
|
|
51
|
-
persistence:
|
|
58
|
+
persistence: { data: { id: 'data', mountPath: '/data', sizeGiB: 10, retention: 'retain' } },
|
|
52
59
|
exposure: 'public',
|
|
53
60
|
replicas: 1,
|
|
54
|
-
dependsOn:
|
|
61
|
+
dependsOn: { database: true },
|
|
55
62
|
} as const satisfies InfraWorkloadSpec;
|
|
56
63
|
|
|
57
64
|
const invalidWorkloads = [
|
|
58
65
|
{ artifact: { kind: 'build', dockerfile: 'Dockerfile' } },
|
|
59
66
|
{ artifact: { kind: 'image', image: '' } },
|
|
60
|
-
{ ports:
|
|
61
|
-
{ ports:
|
|
62
|
-
{ ports:
|
|
63
|
-
{ ports:
|
|
64
|
-
{
|
|
65
|
-
ports: [
|
|
66
|
-
{ name: 'http', port: 80 },
|
|
67
|
-
{ name: 'http', port: 81 },
|
|
68
|
-
],
|
|
69
|
-
},
|
|
67
|
+
{ ports: { http: { port: 0 } } },
|
|
68
|
+
{ ports: { http: { port: 65536 } } },
|
|
69
|
+
{ ports: { http: { port: 1.5 } } },
|
|
70
|
+
{ ports: { http: { port: 80, protocol: 'sctp' } } },
|
|
71
|
+
{ ports: { '': { port: 80 } } },
|
|
70
72
|
{ replicas: -1 },
|
|
71
73
|
{ replicas: NaN },
|
|
72
74
|
{ replicas: 1.5 },
|
|
73
75
|
{ resources: { memoryMiB: Infinity } },
|
|
74
76
|
{ resources: { cpuMillis: 0 } },
|
|
75
|
-
{ persistence:
|
|
76
|
-
{ persistence:
|
|
77
|
-
{ files:
|
|
77
|
+
{ persistence: { data: { id: 'data', mountPath: '/data', sizeGiB: 1 } } },
|
|
78
|
+
{ persistence: { data: { id: 'data', mountPath: '../data', sizeGiB: 1, retention: 'retain' } } },
|
|
79
|
+
{ files: { '/etc/../secret': { kind: 'literal', value: 'x' } } },
|
|
78
80
|
{ health: { kind: 'http', port: 80, path: '/health', failureThreshold: 0 } },
|
|
79
81
|
{ health: { kind: 'tcp', port: 80, path: '/health' } },
|
|
80
82
|
{ health: { kind: 'command', command: [] } },
|
|
@@ -134,7 +136,7 @@ describe('runtime-neutral workload boundary', () => {
|
|
|
134
136
|
expect(
|
|
135
137
|
isInfraEnvironmentSpec({
|
|
136
138
|
deployment: { compute: { provider: 'local' }, runtime: { provider } },
|
|
137
|
-
workloads:
|
|
139
|
+
workloads: { backend: workload },
|
|
138
140
|
}),
|
|
139
141
|
).toBe(true);
|
|
140
142
|
}
|
|
@@ -156,11 +158,11 @@ describe('runtime-neutral workload boundary', () => {
|
|
|
156
158
|
).toBe(true);
|
|
157
159
|
});
|
|
158
160
|
|
|
159
|
-
it('rejects
|
|
161
|
+
it('rejects workload registries whose key disagrees with workload id', () => {
|
|
160
162
|
expect(
|
|
161
163
|
isInfraEnvironmentSpec({
|
|
162
164
|
deployment: { compute: { provider: 'local' }, runtime: { provider: 'k3s' } },
|
|
163
|
-
workloads:
|
|
165
|
+
workloads: { duplicate: workload },
|
|
164
166
|
}),
|
|
165
167
|
).toBe(false);
|
|
166
168
|
});
|
|
@@ -266,7 +268,7 @@ describe('application state boundary', () => {
|
|
|
266
268
|
category: 'developer_tools',
|
|
267
269
|
themeId: 'default',
|
|
268
270
|
},
|
|
269
|
-
themes:
|
|
271
|
+
themes: { default: defaultTheme },
|
|
270
272
|
activeThemeId: 'default',
|
|
271
273
|
screens: {},
|
|
272
274
|
navigator: { type: 'stack', routes: [] },
|
|
@@ -276,7 +278,7 @@ describe('application state boundary', () => {
|
|
|
276
278
|
deployment: { compute: { provider: 'local' }, runtime: { provider: 'minikube' } },
|
|
277
279
|
},
|
|
278
280
|
},
|
|
279
|
-
modules:
|
|
281
|
+
modules: {},
|
|
280
282
|
},
|
|
281
283
|
settings: { localization: { defaultLocale: 'en', locales: ['en'] } },
|
|
282
284
|
} satisfies AppManifest;
|
package/src/infra.test.ts
CHANGED
|
@@ -23,7 +23,7 @@ const production = {
|
|
|
23
23
|
},
|
|
24
24
|
database: { provider: 'supabase' },
|
|
25
25
|
auth: { provider: 'supabase' },
|
|
26
|
-
objectStorage: { provider: 'r2', buckets:
|
|
26
|
+
objectStorage: { provider: 'r2', buckets: { media: true } },
|
|
27
27
|
authz: { provider: 'cerbos', kind: 'ABAC' },
|
|
28
28
|
secretStore: { provider: 'supabase-vault' },
|
|
29
29
|
networking: { domain: 'api.example.ch', publicBaseUrl: 'https://api.example.ch' },
|
|
@@ -33,7 +33,7 @@ describe('standalone Infra environments', () => {
|
|
|
33
33
|
it('parses local/preview/production without an AppManifest or Deploy', () => {
|
|
34
34
|
const manifest = {
|
|
35
35
|
environments: { local, preview: production, production },
|
|
36
|
-
modules:
|
|
36
|
+
modules: {},
|
|
37
37
|
} satisfies InfraManifest;
|
|
38
38
|
expect(parseInfraManifest(JSON.parse(JSON.stringify(manifest)))).toEqual({
|
|
39
39
|
ok: true,
|
|
@@ -45,14 +45,14 @@ describe('standalone Infra environments', () => {
|
|
|
45
45
|
it.each([
|
|
46
46
|
null,
|
|
47
47
|
{},
|
|
48
|
-
{ modules:
|
|
49
|
-
{ environments: {}, modules:
|
|
50
|
-
{ environments: { production }, modules:
|
|
51
|
-
{ environments: { local, staging: local }, modules:
|
|
52
|
-
{ environments: { local, preview: null }, modules:
|
|
53
|
-
{ environments: { local }, modules:
|
|
54
|
-
{ environments: { local }, modules:
|
|
55
|
-
{ environments: { local }, modules:
|
|
48
|
+
{ modules: {} },
|
|
49
|
+
{ environments: {}, modules: {} },
|
|
50
|
+
{ environments: { production }, modules: {} },
|
|
51
|
+
{ environments: { local, staging: local }, modules: {} },
|
|
52
|
+
{ environments: { local, preview: null }, modules: {} },
|
|
53
|
+
{ environments: { local }, modules: { invalid: 42 } },
|
|
54
|
+
{ environments: { local }, modules: {}, modulesConfig: {} },
|
|
55
|
+
{ environments: { local }, modules: {}, apis: 'invalid' },
|
|
56
56
|
])('rejects invalid environment boundaries: %j', (value) => {
|
|
57
57
|
expect(isInfraManifest(value)).toBe(false);
|
|
58
58
|
expect(parseInfraManifest(value).ok).toBe(false);
|
|
@@ -69,7 +69,7 @@ describe('standalone Infra environments', () => {
|
|
|
69
69
|
'plugins',
|
|
70
70
|
'pluginsConfig',
|
|
71
71
|
])('rejects removed top-level %s', (key) => {
|
|
72
|
-
expect(isInfraManifest({ environments: { local }, modules:
|
|
72
|
+
expect(isInfraManifest({ environments: { local }, modules: {}, [key]: {} })).toBe(false);
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
it.each(['storage', 'state', 'monitoring', 'observability', 'target'])(
|
|
@@ -148,21 +148,17 @@ describe('Cerbos policy configuration', () => {
|
|
|
148
148
|
authz: {
|
|
149
149
|
provider: 'cerbos',
|
|
150
150
|
kind: 'ABAC',
|
|
151
|
-
policies:
|
|
151
|
+
policies: { 'app.yaml': 'apiVersion: api.cerbos.dev/v1' },
|
|
152
152
|
},
|
|
153
153
|
}),
|
|
154
154
|
).toBe(true);
|
|
155
155
|
});
|
|
156
156
|
|
|
157
157
|
it.each([
|
|
158
|
-
{ policies:
|
|
159
|
-
{
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
{ path: 'app.yaml', content: 'y' },
|
|
163
|
-
],
|
|
164
|
-
},
|
|
165
|
-
])('rejects unsafe or duplicate policy files: %j', ({ policies }) => {
|
|
158
|
+
{ policies: { '../app.yaml': 'x' } },
|
|
159
|
+
{ policies: { 'app.yaml': 42 } },
|
|
160
|
+
{ policies: [{ path: 'app.yaml', content: 'legacy-array-shape' }] },
|
|
161
|
+
])('rejects unsafe or non-canonical policy files: %j', ({ policies }) => {
|
|
166
162
|
expect(
|
|
167
163
|
isInfraEnvironmentSpec({
|
|
168
164
|
...local,
|
|
@@ -12,7 +12,7 @@ const production = {
|
|
|
12
12
|
},
|
|
13
13
|
database: { provider: 'supabase' },
|
|
14
14
|
auth: { provider: 'supabase' },
|
|
15
|
-
objectStorage: { provider: 'r2', buckets:
|
|
15
|
+
objectStorage: { provider: 'r2', buckets: { media: true } },
|
|
16
16
|
authz: { provider: 'cerbos', kind: 'ABAC' },
|
|
17
17
|
secretStore: { provider: 'supabase-vault' },
|
|
18
18
|
networking: { domain: 'api.example.ch', publicBaseUrl: 'https://api.example.ch' },
|
package/src/requirements.test.ts
CHANGED
|
@@ -11,10 +11,10 @@ describe('platform requirements', () => {
|
|
|
11
11
|
it('exports ebookReader as the canonical reader capability', () => {
|
|
12
12
|
const capability: AnkhorageCapabilityName = 'ebookReader';
|
|
13
13
|
const componentRequirements: ComponentRequirements = {
|
|
14
|
-
capabilities:
|
|
14
|
+
capabilities: { [capability]: true },
|
|
15
15
|
};
|
|
16
16
|
const screenRequirements: ScreenRequirements = {
|
|
17
|
-
capabilities:
|
|
17
|
+
capabilities: { [capability]: true },
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
expect(ANKHORAGE_CAPABILITY_NAMES).toContain(capability);
|
package/src/requirements.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { SerializableSet } from './collections';
|
|
2
|
+
|
|
1
3
|
export const ANKHORAGE_PERMISSION_NAMES = [
|
|
2
4
|
'camera',
|
|
3
5
|
'microphone',
|
|
@@ -24,20 +26,12 @@ export const ANKHORAGE_CAPABILITY_NAMES = [
|
|
|
24
26
|
|
|
25
27
|
export type AnkhorageCapabilityName = (typeof ANKHORAGE_CAPABILITY_NAMES)[number];
|
|
26
28
|
|
|
27
|
-
export interface ScreenPermissionRequirement {
|
|
28
|
-
readonly permission: AnkhoragePermissionName;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface ScreenCapabilityRequirement {
|
|
32
|
-
readonly capability: AnkhorageCapabilityName;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
29
|
export interface ScreenRequirements {
|
|
36
|
-
readonly permissions?:
|
|
37
|
-
readonly capabilities?:
|
|
30
|
+
readonly permissions?: SerializableSet<AnkhoragePermissionName>;
|
|
31
|
+
readonly capabilities?: SerializableSet<AnkhorageCapabilityName>;
|
|
38
32
|
}
|
|
39
33
|
|
|
40
34
|
export interface ComponentRequirements {
|
|
41
|
-
readonly permissions?:
|
|
42
|
-
readonly capabilities?:
|
|
35
|
+
readonly permissions?: SerializableSet<AnkhoragePermissionName>;
|
|
36
|
+
readonly capabilities?: SerializableSet<AnkhorageCapabilityName>;
|
|
43
37
|
}
|
package/src/secrets.test.ts
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { isRecord } from '@ankhorage/utility/object';
|
|
2
|
+
|
|
3
|
+
export type SerializableValue =
|
|
4
|
+
| string
|
|
5
|
+
| number
|
|
6
|
+
| boolean
|
|
7
|
+
| null
|
|
8
|
+
| readonly SerializableValue[]
|
|
9
|
+
| {
|
|
10
|
+
readonly [key: string]: SerializableValue;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/*** Validate recursively serializable manifest/config values without accepting functions or host objects. */
|
|
14
|
+
export function isSerializableValue(value: unknown): value is SerializableValue {
|
|
15
|
+
if (
|
|
16
|
+
value === null ||
|
|
17
|
+
typeof value === 'string' ||
|
|
18
|
+
typeof value === 'number' ||
|
|
19
|
+
typeof value === 'boolean'
|
|
20
|
+
) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
if (Array.isArray(value)) return value.every(isSerializableValue);
|
|
24
|
+
return isRecord(value) && Object.values(value).every(isSerializableValue);
|
|
25
|
+
}
|
package/src/state.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { SerializableValue } from './serializable';
|
|
2
|
+
|
|
1
3
|
/** Legend currently implements in-memory state only; unsupported persistence cannot be selected. */
|
|
2
4
|
export interface AppStateSpec {
|
|
3
5
|
readonly provider: 'legend';
|
|
@@ -6,12 +8,7 @@ export interface AppStateSpec {
|
|
|
6
8
|
|
|
7
9
|
export type StatePrimitive = string | number | boolean | null;
|
|
8
10
|
|
|
9
|
-
export type StateValue =
|
|
10
|
-
| StatePrimitive
|
|
11
|
-
| readonly StateValue[]
|
|
12
|
-
| {
|
|
13
|
-
readonly [key: string]: StateValue;
|
|
14
|
-
};
|
|
11
|
+
export type StateValue = SerializableValue;
|
|
15
12
|
|
|
16
13
|
export type StatePath = string | readonly string[];
|
|
17
14
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { AuthFlowConfig, AuthOAuthConfig } from '../auth';
|
|
2
|
-
import type {
|
|
2
|
+
import type { SerializableSet } from '../collections';
|
|
3
|
+
import type { ApiDefinitionRegistry, DataContractValue } from '../data';
|
|
3
4
|
import type { AppEnvironmentId } from '../environments';
|
|
4
5
|
import type { INFRA_ADAPTER_CATALOG, INFRA_RUNTIME_COMPATIBILITY } from '../infra/constants';
|
|
5
6
|
import type { AuthProfileSpec, AuthScope, AuthSignInSpec, AuthSignUpSpec } from '../types';
|
|
6
7
|
import type { InfraControlPlaneCredentialRef } from './infraSecrets';
|
|
7
|
-
import type {
|
|
8
|
+
import type { InfraWorkloadRegistry } from './infraWorkload';
|
|
8
9
|
|
|
9
10
|
export type InfraAdapterId = keyof typeof INFRA_ADAPTER_CATALOG;
|
|
10
11
|
export type InfraCapability =
|
|
@@ -86,11 +87,11 @@ export interface InfraDatabaseConfigMap {
|
|
|
86
87
|
}
|
|
87
88
|
export interface InfraObjectStorageConfigMap {
|
|
88
89
|
readonly supabase: {
|
|
89
|
-
readonly buckets?:
|
|
90
|
+
readonly buckets?: SerializableSet;
|
|
90
91
|
readonly backend?: InfraS3PersistenceTarget;
|
|
91
92
|
};
|
|
92
93
|
readonly r2: {
|
|
93
|
-
readonly buckets?:
|
|
94
|
+
readonly buckets?: SerializableSet;
|
|
94
95
|
readonly accountId?: string;
|
|
95
96
|
readonly credentials?: InfraControlPlaneCredentialRef;
|
|
96
97
|
};
|
|
@@ -108,13 +109,9 @@ export interface InfraAuthConfigMap {
|
|
|
108
109
|
export interface InfraAuthzConfigMap {
|
|
109
110
|
readonly cerbos: {
|
|
110
111
|
readonly kind: 'RBAC' | 'ABAC';
|
|
111
|
-
readonly policies?:
|
|
112
|
+
readonly policies?: Readonly<Record<string, string>>;
|
|
112
113
|
};
|
|
113
114
|
}
|
|
114
|
-
export interface InfraAuthzPolicyFile {
|
|
115
|
-
readonly path: string;
|
|
116
|
-
readonly content: string;
|
|
117
|
-
}
|
|
118
115
|
export interface InfraSecretStoreConfigMap {
|
|
119
116
|
readonly 'supabase-vault': { readonly schema?: string };
|
|
120
117
|
}
|
|
@@ -161,15 +158,22 @@ export interface InfraEnvironmentSpec {
|
|
|
161
158
|
readonly authz?: InfraAuthzSpec;
|
|
162
159
|
readonly secretStore?: InfraSecretStoreSpec;
|
|
163
160
|
readonly networking?: InfraNetworkingSpec;
|
|
164
|
-
readonly workloads?:
|
|
161
|
+
readonly workloads?: InfraWorkloadRegistry;
|
|
165
162
|
}
|
|
166
163
|
|
|
164
|
+
export type InfraModuleId = string;
|
|
165
|
+
|
|
166
|
+
export interface InfraModuleSpec {
|
|
167
|
+
readonly config?: DataContractValue;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export type InfraModuleRegistry = Readonly<Record<InfraModuleId, InfraModuleSpec>>;
|
|
171
|
+
|
|
167
172
|
export interface InfraManifest {
|
|
168
173
|
readonly environments: Readonly<
|
|
169
174
|
Record<'local', InfraEnvironmentSpec> &
|
|
170
175
|
Partial<Record<Exclude<AppEnvironmentId, 'local'>, InfraEnvironmentSpec>>
|
|
171
176
|
>;
|
|
172
|
-
readonly apis?:
|
|
173
|
-
readonly modules:
|
|
174
|
-
readonly modulesConfig?: Readonly<Record<string, unknown>>;
|
|
177
|
+
readonly apis?: ApiDefinitionRegistry;
|
|
178
|
+
readonly modules: InfraModuleRegistry;
|
|
175
179
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SerializableSet } from '../collections';
|
|
1
2
|
import type { InfraControlPlaneCredentialRef, InfraSecretReference } from './infraSecrets';
|
|
2
3
|
|
|
3
4
|
export interface InfraWorkloadArtifact {
|
|
@@ -25,7 +26,6 @@ export type InfraWorkloadValue =
|
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
export interface InfraWorkloadPort {
|
|
28
|
-
readonly name: string;
|
|
29
29
|
readonly port: number;
|
|
30
30
|
readonly protocol?: 'tcp' | 'udp';
|
|
31
31
|
/** Exact external listener port requested for a public single-replica workload. */
|
|
@@ -57,25 +57,26 @@ export interface InfraWorkloadVolumeSpec {
|
|
|
57
57
|
readonly retention: 'retain' | 'delete-on-destroy';
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
export
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
60
|
+
export type InfraWorkloadId = string;
|
|
61
|
+
export type InfraWorkloadPortRegistry = Readonly<Record<string, InfraWorkloadPort>>;
|
|
62
|
+
export type InfraWorkloadFileMap = Readonly<Record<string, InfraWorkloadValue>>;
|
|
63
|
+
export type InfraWorkloadVolumeRegistry = Readonly<Record<string, InfraWorkloadVolumeSpec>>;
|
|
65
64
|
|
|
66
65
|
export interface InfraWorkloadSpec {
|
|
67
|
-
readonly id:
|
|
66
|
+
readonly id: InfraWorkloadId;
|
|
68
67
|
readonly artifact: InfraWorkloadArtifact;
|
|
69
68
|
readonly command?: readonly string[];
|
|
70
69
|
readonly args?: readonly string[];
|
|
71
|
-
readonly ports?:
|
|
70
|
+
readonly ports?: InfraWorkloadPortRegistry;
|
|
72
71
|
readonly environment?: Readonly<Record<string, InfraWorkloadValue>>;
|
|
73
|
-
readonly files?:
|
|
72
|
+
readonly files?: InfraWorkloadFileMap;
|
|
74
73
|
readonly health?: InfraWorkloadHealthSpec;
|
|
75
74
|
readonly resources?: InfraWorkloadResourceSpec;
|
|
76
|
-
readonly persistence?:
|
|
75
|
+
readonly persistence?: InfraWorkloadVolumeRegistry;
|
|
77
76
|
readonly exposure?: 'internal' | 'public';
|
|
78
77
|
readonly replicas?: number;
|
|
79
78
|
/** IDs in the composed desired-state graph; the orchestrator validates missing/cyclic edges. */
|
|
80
|
-
readonly dependsOn?:
|
|
79
|
+
readonly dependsOn?: SerializableSet;
|
|
81
80
|
}
|
|
81
|
+
|
|
82
|
+
export type InfraWorkloadRegistry = Readonly<Record<InfraWorkloadId, InfraWorkloadSpec>>;
|
package/src/types.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { MediaAssetReference, MediaManifest } from './media';
|
|
|
14
14
|
import type { AppNavigatorManifest } from './navigator';
|
|
15
15
|
import type { RepositoryManifest } from './repository';
|
|
16
16
|
import type { ScreenRequirements } from './requirements';
|
|
17
|
+
import type { SerializableValue } from './serializable';
|
|
17
18
|
import type { AppStateSpec } from './state';
|
|
18
19
|
import type { ThemeGlobalTokenOverrides, ThemeRecipeOverrides } from './theme';
|
|
19
20
|
|
|
@@ -22,8 +23,10 @@ export interface ThemeModeConfig {
|
|
|
22
23
|
harmony: ColorHarmony;
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
export type ThemeId = string;
|
|
27
|
+
|
|
25
28
|
export interface ThemeConfig {
|
|
26
|
-
id:
|
|
29
|
+
id: ThemeId;
|
|
27
30
|
name: string;
|
|
28
31
|
light: ThemeModeConfig;
|
|
29
32
|
dark: ThemeModeConfig;
|
|
@@ -33,6 +36,8 @@ export interface ThemeConfig {
|
|
|
33
36
|
recipes?: ThemeRecipeOverrides;
|
|
34
37
|
}
|
|
35
38
|
|
|
39
|
+
export type ThemeRegistry = Readonly<Record<ThemeId, ThemeConfig>>;
|
|
40
|
+
|
|
36
41
|
export type ActionType =
|
|
37
42
|
'navigate' | 'alert' | 'console' | 'toggleDarkMode' | 'setLanguage' | 'search' | 'filter';
|
|
38
43
|
|
|
@@ -93,13 +98,7 @@ export type Action =
|
|
|
93
98
|
| SetLanguageAction
|
|
94
99
|
| ToggleDarkModeAction;
|
|
95
100
|
|
|
96
|
-
export type ManifestValue =
|
|
97
|
-
| string
|
|
98
|
-
| number
|
|
99
|
-
| boolean
|
|
100
|
-
| null
|
|
101
|
-
| readonly ManifestValue[]
|
|
102
|
-
| { readonly [key: string]: ManifestValue };
|
|
101
|
+
export type ManifestValue = SerializableValue;
|
|
103
102
|
|
|
104
103
|
export type ComponentEventPayloadValue = ManifestValue;
|
|
105
104
|
|
|
@@ -271,12 +270,12 @@ export interface AppManifest {
|
|
|
271
270
|
slug: string;
|
|
272
271
|
version: string;
|
|
273
272
|
category: AppCategory;
|
|
274
|
-
themeId:
|
|
273
|
+
themeId: ThemeId;
|
|
275
274
|
created?: string;
|
|
276
275
|
updated?: string;
|
|
277
276
|
};
|
|
278
|
-
themes:
|
|
279
|
-
activeThemeId:
|
|
277
|
+
themes: ThemeRegistry;
|
|
278
|
+
activeThemeId: ThemeId;
|
|
280
279
|
activeThemeMode?: 'dark' | 'light';
|
|
281
280
|
splashScreen?: SplashScreenSpec;
|
|
282
281
|
/** Studio-managed authoring media. Runtime/user uploads are intentionally separate. */
|
|
@@ -287,7 +286,7 @@ export interface AppManifest {
|
|
|
287
286
|
state?: AppStateSpec;
|
|
288
287
|
infra: InfraManifest;
|
|
289
288
|
navigator: AppNavigatorManifest;
|
|
290
|
-
screens: Record<string, ScreenSpec
|
|
289
|
+
screens: Readonly<Record<string, ScreenSpec>>;
|
|
291
290
|
dataSources?: DataSourceRegistry;
|
|
292
291
|
dataBindings?: ComponentDataBindingRegistry;
|
|
293
292
|
repository?: RepositoryManifest;
|