@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.
Files changed (250) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +10 -2
  3. package/dist/appManifest/apis.d.ts +1 -0
  4. package/dist/appManifest/apis.d.ts.map +1 -1
  5. package/dist/appManifest/apis.js +17 -14
  6. package/dist/appManifest/apis.js.map +1 -1
  7. package/dist/appManifest/bindings.d.ts +3 -0
  8. package/dist/appManifest/bindings.d.ts.map +1 -1
  9. package/dist/appManifest/bindings.js +17 -1
  10. package/dist/appManifest/bindings.js.map +1 -1
  11. package/dist/appManifest/constants.d.ts +18 -0
  12. package/dist/appManifest/constants.d.ts.map +1 -0
  13. package/dist/appManifest/constants.js +18 -0
  14. package/dist/appManifest/constants.js.map +1 -0
  15. package/dist/appManifest/data.d.ts +4 -0
  16. package/dist/appManifest/data.d.ts.map +1 -1
  17. package/dist/appManifest/data.js +22 -3
  18. package/dist/appManifest/data.js.map +1 -1
  19. package/dist/appManifest/dataSources.d.ts +1 -0
  20. package/dist/appManifest/dataSources.d.ts.map +1 -1
  21. package/dist/appManifest/dataSources.js +7 -6
  22. package/dist/appManifest/dataSources.js.map +1 -1
  23. package/dist/appManifest/deploy.d.ts +1 -0
  24. package/dist/appManifest/deploy.d.ts.map +1 -1
  25. package/dist/appManifest/deploy.js +16 -13
  26. package/dist/appManifest/deploy.js.map +1 -1
  27. package/dist/appManifest/icon.d.ts.map +1 -1
  28. package/dist/appManifest/icon.js +2 -1
  29. package/dist/appManifest/icon.js.map +1 -1
  30. package/dist/appManifest/isAppManifest.d.ts +4 -0
  31. package/dist/appManifest/isAppManifest.d.ts.map +1 -0
  32. package/dist/appManifest/isAppManifest.js +69 -0
  33. package/dist/appManifest/isAppManifest.js.map +1 -0
  34. package/dist/appManifest/isAppStateSpec.d.ts +4 -0
  35. package/dist/appManifest/isAppStateSpec.d.ts.map +1 -0
  36. package/dist/appManifest/isAppStateSpec.js +9 -0
  37. package/dist/appManifest/isAppStateSpec.js.map +1 -0
  38. package/dist/appManifest/isManifestValue.d.ts +3 -0
  39. package/dist/appManifest/isManifestValue.d.ts.map +1 -0
  40. package/dist/appManifest/isManifestValue.js +15 -0
  41. package/dist/appManifest/isManifestValue.js.map +1 -0
  42. package/dist/appManifest/media.d.ts +1 -0
  43. package/dist/appManifest/media.d.ts.map +1 -1
  44. package/dist/appManifest/media.js +10 -8
  45. package/dist/appManifest/media.js.map +1 -1
  46. package/dist/appManifest/navigator.d.ts.map +1 -1
  47. package/dist/appManifest/navigator.js +7 -6
  48. package/dist/appManifest/navigator.js.map +1 -1
  49. package/dist/appManifest/navigatorOptions.d.ts +0 -2
  50. package/dist/appManifest/navigatorOptions.d.ts.map +1 -1
  51. package/dist/appManifest/navigatorOptions.js +8 -12
  52. package/dist/appManifest/navigatorOptions.js.map +1 -1
  53. package/dist/appManifest/parseAppManifest.d.ts +10 -0
  54. package/dist/appManifest/parseAppManifest.d.ts.map +1 -0
  55. package/dist/appManifest/parseAppManifest.js +14 -0
  56. package/dist/appManifest/parseAppManifest.js.map +1 -0
  57. package/dist/appManifest/screens.d.ts +4 -0
  58. package/dist/appManifest/screens.d.ts.map +1 -1
  59. package/dist/appManifest/screens.js +14 -2
  60. package/dist/appManifest/screens.js.map +1 -1
  61. package/dist/appManifest.d.ts +3 -18
  62. package/dist/appManifest.d.ts.map +1 -1
  63. package/dist/appManifest.js +2 -80
  64. package/dist/appManifest.js.map +1 -1
  65. package/dist/auth.d.ts +3 -2
  66. package/dist/auth.d.ts.map +1 -1
  67. package/dist/auth.js.map +1 -1
  68. package/dist/deploy.d.ts +0 -9
  69. package/dist/deploy.d.ts.map +1 -1
  70. package/dist/deploy.js +0 -8
  71. package/dist/deploy.js.map +1 -1
  72. package/dist/environments.d.ts +4 -0
  73. package/dist/environments.d.ts.map +1 -0
  74. package/dist/environments.js +3 -0
  75. package/dist/environments.js.map +1 -0
  76. package/dist/index.d.ts +2 -1
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +2 -1
  79. package/dist/index.js.map +1 -1
  80. package/dist/infra/constants.d.ts +91 -0
  81. package/dist/infra/constants.d.ts.map +1 -0
  82. package/dist/infra/constants.js +91 -0
  83. package/dist/infra/constants.js.map +1 -0
  84. package/dist/infra/infraFields.d.ts +12 -0
  85. package/dist/infra/infraFields.d.ts.map +1 -0
  86. package/dist/infra/infraFields.js +14 -0
  87. package/dist/infra/infraFields.js.map +1 -0
  88. package/dist/infra/isInfraAdapterDescriptor.d.ts +4 -0
  89. package/dist/infra/isInfraAdapterDescriptor.d.ts.map +1 -0
  90. package/dist/infra/isInfraAdapterDescriptor.js +31 -0
  91. package/dist/infra/isInfraAdapterDescriptor.js.map +1 -0
  92. package/dist/infra/isInfraAuthSpec.d.ts +4 -0
  93. package/dist/infra/isInfraAuthSpec.d.ts.map +1 -0
  94. package/dist/infra/isInfraAuthSpec.js +75 -0
  95. package/dist/infra/isInfraAuthSpec.js.map +1 -0
  96. package/dist/infra/isInfraCredentialRef.d.ts +3 -0
  97. package/dist/infra/isInfraCredentialRef.d.ts.map +1 -0
  98. package/dist/infra/isInfraCredentialRef.js +10 -0
  99. package/dist/infra/isInfraCredentialRef.js.map +1 -0
  100. package/dist/infra/isInfraDeploymentSpec.d.ts +4 -0
  101. package/dist/infra/isInfraDeploymentSpec.d.ts.map +1 -0
  102. package/dist/infra/isInfraDeploymentSpec.js +66 -0
  103. package/dist/infra/isInfraDeploymentSpec.js.map +1 -0
  104. package/dist/infra/isInfraEnvironmentSpec.d.ts +4 -0
  105. package/dist/infra/isInfraEnvironmentSpec.d.ts.map +1 -0
  106. package/dist/infra/isInfraEnvironmentSpec.js +82 -0
  107. package/dist/infra/isInfraEnvironmentSpec.js.map +1 -0
  108. package/dist/infra/isInfraManifest.d.ts +4 -0
  109. package/dist/infra/isInfraManifest.d.ts.map +1 -0
  110. package/dist/infra/isInfraManifest.js +23 -0
  111. package/dist/infra/isInfraManifest.js.map +1 -0
  112. package/dist/infra/isInfraShape.d.ts +3 -0
  113. package/dist/infra/isInfraShape.d.ts.map +1 -0
  114. package/dist/infra/isInfraShape.js +10 -0
  115. package/dist/infra/isInfraShape.js.map +1 -0
  116. package/dist/infra/isInfraWorkloadHealth.d.ts +3 -0
  117. package/dist/infra/isInfraWorkloadHealth.d.ts.map +1 -0
  118. package/dist/infra/isInfraWorkloadHealth.js +37 -0
  119. package/dist/infra/isInfraWorkloadHealth.js.map +1 -0
  120. package/dist/infra/isInfraWorkloadSpec.d.ts +4 -0
  121. package/dist/infra/isInfraWorkloadSpec.d.ts.map +1 -0
  122. package/dist/infra/isInfraWorkloadSpec.js +70 -0
  123. package/dist/infra/isInfraWorkloadSpec.js.map +1 -0
  124. package/dist/infra/isInfraWorkloadValue.d.ts +3 -0
  125. package/dist/infra/isInfraWorkloadValue.d.ts.map +1 -0
  126. package/dist/infra/isInfraWorkloadValue.js +40 -0
  127. package/dist/infra/isInfraWorkloadValue.js.map +1 -0
  128. package/dist/infra/parseInfraManifest.d.ts +5 -0
  129. package/dist/infra/parseInfraManifest.d.ts.map +1 -0
  130. package/dist/infra/parseInfraManifest.js +17 -0
  131. package/dist/infra/parseInfraManifest.js.map +1 -0
  132. package/dist/infra/validateInfraAdapterSelection.d.ts +6 -0
  133. package/dist/infra/validateInfraAdapterSelection.d.ts.map +1 -0
  134. package/dist/infra/validateInfraAdapterSelection.js +36 -0
  135. package/dist/infra/validateInfraAdapterSelection.js.map +1 -0
  136. package/dist/infra.d.ts +16 -0
  137. package/dist/infra.d.ts.map +1 -0
  138. package/dist/infra.js +11 -0
  139. package/dist/infra.js.map +1 -0
  140. package/dist/media.d.ts +7 -6
  141. package/dist/media.d.ts.map +1 -1
  142. package/dist/media.js +5 -5
  143. package/dist/media.js.map +1 -1
  144. package/dist/state.d.ts +5 -0
  145. package/dist/state.d.ts.map +1 -1
  146. package/dist/state.js.map +1 -1
  147. package/dist/types/appManifest.d.ts +9 -0
  148. package/dist/types/appManifest.d.ts.map +1 -0
  149. package/dist/types/appManifest.js +2 -0
  150. package/dist/types/appManifest.js.map +1 -0
  151. package/dist/types/infraAdapters.d.ts +85 -0
  152. package/dist/types/infraAdapters.d.ts.map +1 -0
  153. package/dist/types/infraAdapters.js +2 -0
  154. package/dist/types/infraAdapters.js.map +1 -0
  155. package/dist/types/infraLifecycle.d.ts +107 -0
  156. package/dist/types/infraLifecycle.d.ts.map +1 -0
  157. package/dist/types/infraLifecycle.js +2 -0
  158. package/dist/types/infraLifecycle.js.map +1 -0
  159. package/dist/types/infraManifest.d.ts +142 -0
  160. package/dist/types/infraManifest.d.ts.map +1 -0
  161. package/dist/types/infraManifest.js +2 -0
  162. package/dist/types/infraManifest.js.map +1 -0
  163. package/dist/types/infraSecrets.d.ts +15 -0
  164. package/dist/types/infraSecrets.d.ts.map +1 -0
  165. package/dist/types/infraSecrets.js +2 -0
  166. package/dist/types/infraSecrets.js.map +1 -0
  167. package/dist/types/infraValidation.d.ts +5 -0
  168. package/dist/types/infraValidation.d.ts.map +1 -0
  169. package/dist/types/infraValidation.js +2 -0
  170. package/dist/types/infraValidation.js.map +1 -0
  171. package/dist/types/infraWorkload.d.ts +70 -0
  172. package/dist/types/infraWorkload.d.ts.map +1 -0
  173. package/dist/types/infraWorkload.js +2 -0
  174. package/dist/types/infraWorkload.js.map +1 -0
  175. package/dist/types.d.ts +7 -70
  176. package/dist/types.d.ts.map +1 -1
  177. package/dist/types.js +0 -9
  178. package/dist/types.js.map +1 -1
  179. package/package.json +11 -2
  180. package/src/appManifest/apis.ts +18 -16
  181. package/src/appManifest/bindings.ts +18 -1
  182. package/src/appManifest/constants.ts +19 -0
  183. package/src/appManifest/data.ts +23 -9
  184. package/src/appManifest/dataSources.ts +8 -7
  185. package/src/appManifest/deploy.ts +17 -15
  186. package/src/appManifest/icon.ts +3 -1
  187. package/src/appManifest/isAppManifest.ts +95 -0
  188. package/src/appManifest/isAppStateSpec.ts +13 -0
  189. package/src/appManifest/isManifestValue.ts +19 -0
  190. package/src/appManifest/media.ts +11 -10
  191. package/src/appManifest/navigator.ts +7 -6
  192. package/src/appManifest/navigatorOptions.ts +9 -16
  193. package/src/appManifest/parseAppManifest.ts +15 -0
  194. package/src/appManifest/screens.ts +14 -2
  195. package/src/appManifest.test.ts +9 -5
  196. package/src/appManifest.ts +3 -107
  197. package/src/auth-flow-contract.test.ts +6 -10
  198. package/src/auth-oauth.test.ts +2 -2
  199. package/src/auth.ts +3 -2
  200. package/src/bindings.test.ts +5 -0
  201. package/src/contracts.test.ts +21 -19
  202. package/src/deploy.test.ts +13 -5
  203. package/src/deploy.ts +0 -11
  204. package/src/environments.ts +4 -0
  205. package/src/index.ts +2 -1
  206. package/src/infra/constants.ts +91 -0
  207. package/src/infra/infraFields.ts +20 -0
  208. package/src/infra/isInfraAdapterDescriptor.ts +37 -0
  209. package/src/infra/isInfraAuthSpec.ts +98 -0
  210. package/src/infra/isInfraCredentialRef.ts +11 -0
  211. package/src/infra/isInfraDeploymentSpec.ts +75 -0
  212. package/src/infra/isInfraEnvironmentSpec.ts +95 -0
  213. package/src/infra/isInfraManifest.ts +29 -0
  214. package/src/infra/isInfraShape.ts +16 -0
  215. package/src/infra/isInfraWorkloadHealth.ts +38 -0
  216. package/src/infra/isInfraWorkloadSpec.ts +87 -0
  217. package/src/infra/isInfraWorkloadValue.ts +41 -0
  218. package/src/infra/parseInfraManifest.ts +20 -0
  219. package/src/infra/validateInfraAdapterSelection.ts +42 -0
  220. package/src/infra-types.test.ts +78 -0
  221. package/src/infra-workload.test.ts +186 -0
  222. package/src/infra.test.ts +268 -0
  223. package/src/infra.ts +15 -0
  224. package/src/media.ts +12 -11
  225. package/src/profile-contract.test.ts +2 -3
  226. package/src/secrets.test.ts +19 -13
  227. package/src/state.ts +6 -0
  228. package/src/types/appManifest.ts +5 -0
  229. package/src/types/infraAdapters.ts +148 -0
  230. package/src/types/infraLifecycle.ts +105 -0
  231. package/src/types/infraManifest.ts +130 -0
  232. package/src/types/infraSecrets.ts +16 -0
  233. package/src/types/infraValidation.ts +2 -0
  234. package/src/types/infraWorkload.ts +64 -0
  235. package/src/types.ts +7 -87
  236. package/dist/appManifest/infra.d.ts +0 -2
  237. package/dist/appManifest/infra.d.ts.map +0 -1
  238. package/dist/appManifest/infra.js +0 -130
  239. package/dist/appManifest/infra.js.map +0 -1
  240. package/dist/appManifest/shared.d.ts +0 -8
  241. package/dist/appManifest/shared.d.ts.map +0 -1
  242. package/dist/appManifest/shared.js +0 -31
  243. package/dist/appManifest/shared.js.map +0 -1
  244. package/dist/secretManifest.d.ts +0 -11
  245. package/dist/secretManifest.d.ts.map +0 -1
  246. package/dist/secretManifest.js +0 -2
  247. package/dist/secretManifest.js.map +0 -1
  248. package/src/appManifest/infra.ts +0 -190
  249. package/src/appManifest/shared.ts +0 -40
  250. package/src/secretManifest.ts +0 -12
@@ -1,6 +1,9 @@
1
+ import { hasOnlyKeys, isRecord } from '@ankhorage/utility/object';
2
+ import { isNonEmptyString, isOptionalString } from '@ankhorage/utility/string';
3
+
1
4
  import type { ApiDefinition, ApiDefinitionList } from '../data';
2
5
  import { isCredentialRef, isDataEndpointRegistry, isDataSchemaRegistry } from './data';
3
- import { isManifestValue, isOptionalString, isRecord } from './shared';
6
+ import { isManifestValue } from './isManifestValue';
4
7
 
5
8
  const API_BASE_KEYS = [
6
9
  'id',
@@ -13,18 +16,20 @@ const API_BASE_KEYS = [
13
16
  'schemas',
14
17
  'metadata',
15
18
  ] as const;
16
- const EXTERNAL_REST_KEYS = new Set([...API_BASE_KEYS, 'baseUrl', 'openApi']);
17
- const EXTERNAL_GRAPHQL_KEYS = new Set([...API_BASE_KEYS, 'endpointUrl', 'introspection']);
18
- const INTERNAL_REST_KEYS = new Set([...API_BASE_KEYS, 'basePath']);
19
- const OPEN_API_KEYS = new Set(['url', 'documentId', 'version']);
20
- const INTROSPECTION_KEYS = new Set(['enabled', 'schemaVersion']);
19
+ const EXTERNAL_REST_KEYS = [...API_BASE_KEYS, 'baseUrl', 'openApi'] as const;
20
+ const EXTERNAL_GRAPHQL_KEYS = [...API_BASE_KEYS, 'endpointUrl', 'introspection'] as const;
21
+ const INTERNAL_REST_KEYS = [...API_BASE_KEYS, 'basePath'] as const;
22
+ const OPEN_API_KEYS = ['url', 'documentId', 'version'] as const;
23
+ const INTROSPECTION_KEYS = ['enabled', 'schemaVersion'] as const;
21
24
 
25
+ /*** Validate API definitions and require unique API identities. */
22
26
  export function isApiDefinitionList(value: unknown): value is ApiDefinitionList {
23
27
  if (!Array.isArray(value) || !value.every(isApiDefinition)) return false;
24
28
  const ids = value.map((api) => api.id);
25
29
  return new Set(ids).size === ids.length;
26
30
  }
27
31
 
32
+ /*** Validate one API definition against its origin and protocol branch. */
28
33
  function isApiDefinition(value: unknown): value is ApiDefinition {
29
34
  if (!isApiBaseDefinition(value)) return false;
30
35
  if (value.origin === 'external' && value.protocol === 'rest') return isExternalRestApi(value);
@@ -35,14 +40,14 @@ function isApiDefinition(value: unknown): value is ApiDefinition {
35
40
  return false;
36
41
  }
37
42
 
43
+ /*** Validate common API identity, endpoint, schema and authored metadata fields. */
38
44
  function isApiBaseDefinition(value: unknown): value is Record<string, unknown> {
39
45
  return (
40
46
  isRecord(value) &&
41
47
  isNonEmptyString(value.id) &&
42
48
  (value.origin === 'external' || value.origin === 'internal') &&
43
49
  (value.protocol === 'graphql' || value.protocol === 'rest') &&
44
- isOptionalString(value.name) &&
45
- isOptionalString(value.description) &&
50
+ [value.name, value.description].every(isOptionalString) &&
46
51
  (value.credential === undefined || isCredentialRef(value.credential)) &&
47
52
  isDataEndpointRegistry(value.endpoints) &&
48
53
  (value.schemas === undefined || isDataSchemaRegistry(value.schemas)) &&
@@ -50,6 +55,7 @@ function isApiBaseDefinition(value: unknown): value is Record<string, unknown> {
50
55
  );
51
56
  }
52
57
 
58
+ /*** Validate external REST endpoint and optional OpenAPI metadata. */
53
59
  function isExternalRestApi(value: Record<string, unknown>): boolean {
54
60
  return (
55
61
  hasOnlyKeys(value, EXTERNAL_REST_KEYS) &&
@@ -58,6 +64,7 @@ function isExternalRestApi(value: Record<string, unknown>): boolean {
58
64
  );
59
65
  }
60
66
 
67
+ /*** Validate external GraphQL endpoint and optional introspection metadata. */
61
68
  function isExternalGraphQlApi(value: Record<string, unknown>): boolean {
62
69
  return (
63
70
  hasOnlyKeys(value, EXTERNAL_GRAPHQL_KEYS) &&
@@ -66,10 +73,12 @@ function isExternalGraphQlApi(value: Record<string, unknown>): boolean {
66
73
  );
67
74
  }
68
75
 
76
+ /*** Validate the supported internal REST API configuration. */
69
77
  function isInternalRestApi(value: Record<string, unknown>): boolean {
70
78
  return hasOnlyKeys(value, INTERNAL_REST_KEYS) && isNonEmptyString(value.basePath);
71
79
  }
72
80
 
81
+ /*** Validate optional OpenAPI document location and version fields. */
73
82
  function isOpenApiDocumentRef(value: unknown): boolean {
74
83
  return (
75
84
  isRecord(value) &&
@@ -80,6 +89,7 @@ function isOpenApiDocumentRef(value: unknown): boolean {
80
89
  );
81
90
  }
82
91
 
92
+ /*** Validate explicit GraphQL introspection settings. */
83
93
  function isGraphQlIntrospection(value: unknown): boolean {
84
94
  return (
85
95
  isRecord(value) &&
@@ -88,11 +98,3 @@ function isGraphQlIntrospection(value: unknown): boolean {
88
98
  isOptionalString(value.schemaVersion)
89
99
  );
90
100
  }
91
-
92
- function isNonEmptyString(value: unknown): value is string {
93
- return typeof value === 'string' && value.trim().length > 0;
94
- }
95
-
96
- function hasOnlyKeys(value: Record<string, unknown>, allowed: ReadonlySet<string>): boolean {
97
- return Object.keys(value).every((key) => allowed.has(key));
98
- }
@@ -1,9 +1,14 @@
1
- import { isManifestValue, isOptionalString, isRecord } from './shared';
1
+ import { isRecord } from '@ankhorage/utility/object';
2
+ import { isOptionalString } from '@ankhorage/utility/string';
2
3
 
4
+ import { isManifestValue } from './isManifestValue';
5
+
6
+ /*** Validate every component binding in the authored registry. */
3
7
  export function isComponentDataBindingRegistry(value: unknown): boolean {
4
8
  return isRecord(value) && Object.values(value).every(isComponentDataBinding);
5
9
  }
6
10
 
11
+ /*** Validate literal, operation and path-based binding sources. */
7
12
  export function isBindingValueSource(value: unknown): boolean {
8
13
  return (
9
14
  isRecord(value) &&
@@ -17,6 +22,7 @@ export function isBindingValueSource(value: unknown): boolean {
17
22
  );
18
23
  }
19
24
 
25
+ /*** Validate a screen operation loader and its optional input mapping. */
20
26
  export function isScreenDataLoaderDefinition(value: unknown): boolean {
21
27
  return (
22
28
  isRecord(value) &&
@@ -27,6 +33,7 @@ export function isScreenDataLoaderDefinition(value: unknown): boolean {
27
33
  );
28
34
  }
29
35
 
36
+ /*** Validate component identity and its property and event bindings. */
30
37
  function isComponentDataBinding(value: unknown): boolean {
31
38
  return (
32
39
  isRecord(value) &&
@@ -42,6 +49,7 @@ function isComponentDataBinding(value: unknown): boolean {
42
49
  );
43
50
  }
44
51
 
52
+ /*** Validate a property binding with optional transforms and fallback behavior. */
45
53
  function isPropBinding(value: unknown): boolean {
46
54
  return (
47
55
  isRecord(value) &&
@@ -54,6 +62,7 @@ function isPropBinding(value: unknown): boolean {
54
62
  );
55
63
  }
56
64
 
65
+ /*** Validate an event binding and its declared target. */
57
66
  function isEventBinding(value: unknown): boolean {
58
67
  return (
59
68
  isRecord(value) &&
@@ -63,6 +72,7 @@ function isEventBinding(value: unknown): boolean {
63
72
  );
64
73
  }
65
74
 
75
+ /*** Validate the selected operation or action event target. */
66
76
  function isEventBindingTarget(value: unknown): boolean {
67
77
  return (
68
78
  isRecord(value) &&
@@ -71,6 +81,7 @@ function isEventBindingTarget(value: unknown): boolean {
71
81
  );
72
82
  }
73
83
 
84
+ /*** Validate a binding condition and its source value. */
74
85
  function isBindingCondition(value: unknown): boolean {
75
86
  return (
76
87
  isRecord(value) &&
@@ -80,6 +91,7 @@ function isBindingCondition(value: unknown): boolean {
80
91
  );
81
92
  }
82
93
 
94
+ /*** Validate API and operation identities with an optional endpoint reference. */
83
95
  function isBindingOperationRef(value: unknown): boolean {
84
96
  return (
85
97
  isRecord(value) &&
@@ -89,6 +101,7 @@ function isBindingOperationRef(value: unknown): boolean {
89
101
  );
90
102
  }
91
103
 
104
+ /*** Validate authored binding fallback values. */
92
105
  function isBindingFallback(value: unknown): boolean {
93
106
  return (
94
107
  isRecord(value) &&
@@ -97,6 +110,7 @@ function isBindingFallback(value: unknown): boolean {
97
110
  );
98
111
  }
99
112
 
113
+ /*** Validate loading, empty and error binding behavior. */
100
114
  function isBindingLifecycleBehavior(value: unknown): boolean {
101
115
  return (
102
116
  isRecord(value) &&
@@ -107,6 +121,7 @@ function isBindingLifecycleBehavior(value: unknown): boolean {
107
121
  );
108
122
  }
109
123
 
124
+ /*** Validate optional ordered binding transformations. */
110
125
  function isOptionalBindingTransforms(value: unknown): boolean {
111
126
  return (
112
127
  value === undefined ||
@@ -115,10 +130,12 @@ function isOptionalBindingTransforms(value: unknown): boolean {
115
130
  );
116
131
  }
117
132
 
133
+ /*** Validate every value in an operation input mapping. */
118
134
  function isBindingInputMap(value: unknown): boolean {
119
135
  return isRecord(value) && Object.values(value).every(isBindingInputValue);
120
136
  }
121
137
 
138
+ /*** Validate recursive array, object, literal and source operation inputs. */
122
139
  function isBindingInputValue(value: unknown): boolean {
123
140
  return (
124
141
  isRecord(value) &&
@@ -0,0 +1,19 @@
1
+ import type { AppManifest } from '../types';
2
+
3
+ export const APP_MANIFEST_KEY_POLICY = {
4
+ metadata: 'required',
5
+ themes: 'required',
6
+ activeThemeId: 'required',
7
+ activeThemeMode: 'optional',
8
+ splashScreen: 'optional',
9
+ media: 'optional',
10
+ deploy: 'optional',
11
+ state: 'optional',
12
+ infra: 'required',
13
+ navigator: 'required',
14
+ screens: 'required',
15
+ dataSources: 'optional',
16
+ dataBindings: 'optional',
17
+ repository: 'optional',
18
+ settings: 'required',
19
+ } as const satisfies Record<keyof AppManifest, 'optional' | 'required'>;
@@ -1,10 +1,8 @@
1
- import {
2
- isManifestValue,
3
- isOptionalBoolean,
4
- isOptionalString,
5
- isRecord,
6
- isStringArray,
7
- } from './shared';
1
+ import { isStringArray } from '@ankhorage/utility/array';
2
+ import { isRecord } from '@ankhorage/utility/object';
3
+ import { isOptionalString } from '@ankhorage/utility/string';
4
+
5
+ import { isManifestValue } from './isManifestValue';
8
6
 
9
7
  const DATA_SCHEMA_TYPES = new Set([
10
8
  'array',
@@ -18,14 +16,17 @@ const DATA_SCHEMA_TYPES = new Set([
18
16
  const OPERATION_INTENTS = new Set(['action', 'create', 'delete', 'read', 'update']);
19
17
  const PARAMETER_LOCATIONS = new Set(['body', 'cookie', 'header', 'path', 'query']);
20
18
 
19
+ /*** Validate every endpoint in the data endpoint registry. */
21
20
  export function isDataEndpointRegistry(value: unknown): boolean {
22
21
  return isRecord(value) && Object.values(value).every(isDataEndpointConfig);
23
22
  }
24
23
 
24
+ /*** Validate every schema in the data schema registry. */
25
25
  export function isDataSchemaRegistry(value: unknown): boolean {
26
26
  return isRecord(value) && Object.values(value).every(isDataSchema);
27
27
  }
28
28
 
29
+ /*** Validate credential identity and optional descriptive metadata. */
29
30
  export function isCredentialRef(value: unknown): boolean {
30
31
  return (
31
32
  isRecord(value) &&
@@ -36,6 +37,7 @@ export function isCredentialRef(value: unknown): boolean {
36
37
  );
37
38
  }
38
39
 
40
+ /*** Validate an adapter reference and its optional authored configuration. */
39
41
  export function isAdapterRef(value: unknown): boolean {
40
42
  return (
41
43
  isRecord(value) &&
@@ -47,6 +49,7 @@ export function isAdapterRef(value: unknown): boolean {
47
49
  );
48
50
  }
49
51
 
52
+ /*** Validate endpoint identity, operations and optional connection metadata. */
50
53
  function isDataEndpointConfig(value: unknown): boolean {
51
54
  return (
52
55
  isRecord(value) &&
@@ -63,6 +66,7 @@ function isDataEndpointConfig(value: unknown): boolean {
63
66
  );
64
67
  }
65
68
 
69
+ /*** Validate operation protocol, intent, request and response configuration. */
66
70
  function isDataOperationConfig(value: unknown): boolean {
67
71
  return (
68
72
  isRecord(value) &&
@@ -83,6 +87,7 @@ function isDataOperationConfig(value: unknown): boolean {
83
87
  );
84
88
  }
85
89
 
90
+ /*** Validate request schema, parameters and optional content type. */
86
91
  function isDataOperationRequest(value: unknown): boolean {
87
92
  return (
88
93
  isRecord(value) &&
@@ -93,6 +98,7 @@ function isDataOperationRequest(value: unknown): boolean {
93
98
  );
94
99
  }
95
100
 
101
+ /*** Validate parameter identity, location, schema and optional default value. */
96
102
  function isDataOperationParameter(value: unknown): boolean {
97
103
  return (
98
104
  isRecord(value) &&
@@ -100,12 +106,13 @@ function isDataOperationParameter(value: unknown): boolean {
100
106
  typeof value.name === 'string' &&
101
107
  typeof value.location === 'string' &&
102
108
  PARAMETER_LOCATIONS.has(value.location) &&
103
- isOptionalBoolean(value.required) &&
109
+ (value.required === undefined || typeof value.required === 'boolean') &&
104
110
  isOptionalString(value.description) &&
105
111
  (value.default === undefined || isManifestValue(value.default))
106
112
  );
107
113
  }
108
114
 
115
+ /*** Validate response status, schema and optional descriptive metadata. */
109
116
  function isDataOperationResponse(value: unknown): boolean {
110
117
  return (
111
118
  isRecord(value) &&
@@ -118,6 +125,7 @@ function isDataOperationResponse(value: unknown): boolean {
118
125
  );
119
126
  }
120
127
 
128
+ /*** Validate inline schema and schema-reference fields. */
121
129
  function isDataSchemaSlot(value: Record<string, unknown>): boolean {
122
130
  return (
123
131
  (value.schema === undefined || isDataSchema(value.schema)) &&
@@ -125,6 +133,7 @@ function isDataSchemaSlot(value: Record<string, unknown>): boolean {
125
133
  );
126
134
  }
127
135
 
136
+ /*** Validate supported schema types, constraints and compositions. */
128
137
  function isDataSchema(value: unknown): boolean {
129
138
  if (!isRecord(value) || !isDataSchemaType(value.type)) return false;
130
139
  if (!isOptionalSchemaScalars(value)) return false;
@@ -132,6 +141,7 @@ function isDataSchema(value: unknown): boolean {
132
141
  return isOptionalSchemaComposition(value);
133
142
  }
134
143
 
144
+ /*** Validate a supported schema type or an array of supported types. */
135
145
  function isDataSchemaType(value: unknown): boolean {
136
146
  if (value === undefined) return true;
137
147
  if (typeof value === 'string') return DATA_SCHEMA_TYPES.has(value);
@@ -141,12 +151,13 @@ function isDataSchemaType(value: unknown): boolean {
141
151
  );
142
152
  }
143
153
 
154
+ /*** Validate optional scalar schema constraints. */
144
155
  function isOptionalSchemaScalars(value: Record<string, unknown>): boolean {
145
156
  return (
146
157
  isOptionalString(value.title) &&
147
158
  isOptionalString(value.description) &&
148
159
  isOptionalString(value.format) &&
149
- isOptionalBoolean(value.nullable) &&
160
+ (value.nullable === undefined || typeof value.nullable === 'boolean') &&
150
161
  (value.const === undefined || isManifestValue(value.const)) &&
151
162
  (value.default === undefined || isManifestValue(value.default)) &&
152
163
  (value.enum === undefined ||
@@ -155,6 +166,7 @@ function isOptionalSchemaScalars(value: Record<string, unknown>): boolean {
155
166
  );
156
167
  }
157
168
 
169
+ /*** Validate optional schema properties, items and required fields. */
158
170
  function isOptionalSchemaCollections(value: Record<string, unknown>): boolean {
159
171
  return (
160
172
  (value.required === undefined || isStringArray(value.required)) &&
@@ -167,6 +179,7 @@ function isOptionalSchemaCollections(value: Record<string, unknown>): boolean {
167
179
  );
168
180
  }
169
181
 
182
+ /*** Validate optional schema alternatives and intersections. */
170
183
  function isOptionalSchemaComposition(value: Record<string, unknown>): boolean {
171
184
  return ['allOf', 'anyOf', 'oneOf'].every((key) => {
172
185
  const entry = value[key];
@@ -174,6 +187,7 @@ function isOptionalSchemaComposition(value: Record<string, unknown>): boolean {
174
187
  });
175
188
  }
176
189
 
190
+ /*** Validate a named schema reference. */
177
191
  function isDataSchemaRef(value: unknown): boolean {
178
192
  return isRecord(value) && typeof value.id === 'string';
179
193
  }
@@ -1,12 +1,15 @@
1
+ import { hasOnlyKeys, isRecord } from '@ankhorage/utility/object';
2
+ import { isOptionalString } from '@ankhorage/utility/string';
3
+
1
4
  import {
2
5
  isAdapterRef,
3
6
  isCredentialRef,
4
7
  isDataEndpointRegistry,
5
8
  isDataSchemaRegistry,
6
9
  } from './data';
7
- import { isManifestValue, isOptionalString, isRecord } from './shared';
10
+ import { isManifestValue } from './isManifestValue';
8
11
 
9
- const DATABASE_SOURCE_KEYS = new Set([
12
+ const DATABASE_SOURCE_KEYS = [
10
13
  'id',
11
14
  'kind',
12
15
  'name',
@@ -16,8 +19,9 @@ const DATABASE_SOURCE_KEYS = new Set([
16
19
  'endpoints',
17
20
  'schemas',
18
21
  'metadata',
19
- ]);
22
+ ] as const;
20
23
 
24
+ /*** Validate the supported data-source entries in the registry. */
21
25
  export function isDataSourceRegistry(value: unknown): boolean {
22
26
  return (
23
27
  isRecord(value) &&
@@ -25,6 +29,7 @@ export function isDataSourceRegistry(value: unknown): boolean {
25
29
  );
26
30
  }
27
31
 
32
+ /*** Validate database adapter identity and supported configuration fields. */
28
33
  function isDatabaseDataSource(value: unknown): value is Record<string, unknown> {
29
34
  return (
30
35
  isRecord(value) &&
@@ -42,7 +47,3 @@ function isDatabaseDataSource(value: unknown): value is Record<string, unknown>
42
47
  (value.metadata === undefined || isManifestValue(value.metadata))
43
48
  );
44
49
  }
45
-
46
- function hasOnlyKeys(value: Record<string, unknown>, allowed: ReadonlySet<string>): boolean {
47
- return Object.keys(value).every((key) => allowed.has(key));
48
- }
@@ -1,3 +1,6 @@
1
+ import { hasOnlyKeys, isRecord } from '@ankhorage/utility/object';
2
+ import { isNonEmptyString } from '@ankhorage/utility/string';
3
+
1
4
  import type {
2
5
  AppDeployAndroidTargetConfig,
3
6
  AppDeployIosTargetConfig,
@@ -6,20 +9,21 @@ import type {
6
9
  AppDeployTargets,
7
10
  AppDeployWebTargetConfig,
8
11
  } from '../deploy';
9
- import { isRecord } from './shared';
10
12
 
11
- const DEPLOY_KEYS = new Set(['targets']);
12
- const TARGET_KEYS = new Set(['web', 'android', 'ios']);
13
- const PROVIDER_KEYS = new Set(['build', 'publish']);
14
- const WEB_KEYS = new Set(['enabled', 'providers']);
15
- const ANDROID_KEYS = new Set(['enabled', 'package', 'scheme', 'providers']);
16
- const IOS_KEYS = new Set(['enabled', 'bundleIdentifier', 'scheme', 'providers']);
13
+ const DEPLOY_KEYS = ['targets'] as const;
14
+ const TARGET_KEYS = ['web', 'android', 'ios'] as const;
15
+ const PROVIDER_KEYS = ['build', 'publish'] as const;
16
+ const WEB_KEYS = ['enabled', 'providers'] as const;
17
+ const ANDROID_KEYS = ['enabled', 'package', 'scheme', 'providers'] as const;
18
+ const IOS_KEYS = ['enabled', 'bundleIdentifier', 'scheme', 'providers'] as const;
17
19
  const URI_SCHEME_PATTERN = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
18
20
 
21
+ /*** Validate authored application deployment configuration. */
19
22
  export function isAppDeployManifest(value: unknown): value is AppDeployManifest {
20
23
  return isRecord(value) && hasOnlyKeys(value, DEPLOY_KEYS) && isAppDeployTargets(value.targets);
21
24
  }
22
25
 
26
+ /*** Validate the optional web, Android and iOS deployment targets. */
23
27
  function isAppDeployTargets(value: unknown): value is AppDeployTargets {
24
28
  return (
25
29
  isRecord(value) &&
@@ -30,6 +34,7 @@ function isAppDeployTargets(value: unknown): value is AppDeployTargets {
30
34
  );
31
35
  }
32
36
 
37
+ /*** Validate web deployment identity and provider selection. */
33
38
  function isWebTarget(value: unknown): value is AppDeployWebTargetConfig {
34
39
  return (
35
40
  isRecord(value) &&
@@ -39,6 +44,7 @@ function isWebTarget(value: unknown): value is AppDeployWebTargetConfig {
39
44
  );
40
45
  }
41
46
 
47
+ /*** Validate Android deployment identity, scheme and provider selection. */
42
48
  function isAndroidTarget(value: unknown): value is AppDeployAndroidTargetConfig {
43
49
  return (
44
50
  isRecord(value) &&
@@ -50,6 +56,7 @@ function isAndroidTarget(value: unknown): value is AppDeployAndroidTargetConfig
50
56
  );
51
57
  }
52
58
 
59
+ /*** Validate iOS deployment identity, scheme and provider selection. */
53
60
  function isIosTarget(value: unknown): value is AppDeployIosTargetConfig {
54
61
  return (
55
62
  isRecord(value) &&
@@ -61,14 +68,17 @@ function isIosTarget(value: unknown): value is AppDeployIosTargetConfig {
61
68
  );
62
69
  }
63
70
 
71
+ /*** Accept an omitted scheme or a non-empty authored scheme. */
64
72
  function isOptionalScheme(value: unknown): value is string | undefined {
65
73
  return value === undefined || (typeof value === 'string' && URI_SCHEME_PATTERN.test(value));
66
74
  }
67
75
 
76
+ /*** Accept omitted deployment providers or a valid provider selection. */
68
77
  function isOptionalProviders(value: unknown): value is AppDeployProviderSelection | undefined {
69
78
  return value === undefined || isProviderSelection(value);
70
79
  }
71
80
 
81
+ /*** Validate deployment provider identities and supported selection keys. */
72
82
  function isProviderSelection(value: unknown): value is AppDeployProviderSelection {
73
83
  return (
74
84
  isRecord(value) &&
@@ -77,11 +87,3 @@ function isProviderSelection(value: unknown): value is AppDeployProviderSelectio
77
87
  (value.publish === undefined || isNonEmptyString(value.publish))
78
88
  );
79
89
  }
80
-
81
- function isNonEmptyString(value: unknown): value is string {
82
- return typeof value === 'string' && value.trim().length > 0;
83
- }
84
-
85
- function hasOnlyKeys(value: Record<string, unknown>, allowed: ReadonlySet<string>): boolean {
86
- return Object.keys(value).every((key) => allowed.has(key));
87
- }
@@ -1,5 +1,7 @@
1
+ import { isRecord } from '@ankhorage/utility/object';
2
+ import { isOptionalString } from '@ankhorage/utility/string';
3
+
1
4
  import { isMediaAssetReference } from '../media';
2
- import { isOptionalString, isRecord } from './shared';
3
5
 
4
6
  /*** Validate a serializable icon as either a named font glyph or an SVG media reference. */
5
7
  export function isIconSpec(value: unknown): boolean {
@@ -0,0 +1,95 @@
1
+ import { isStringArray } from '@ankhorage/utility/array';
2
+ import { isRecord } from '@ankhorage/utility/object';
3
+
4
+ import { isInfraManifest } from '../infra/isInfraManifest';
5
+ import type { AppManifest } from '../types';
6
+ import { isComponentDataBindingRegistry } from './bindings';
7
+ import { APP_MANIFEST_KEY_POLICY } from './constants';
8
+ import { isDataSourceRegistry } from './dataSources';
9
+ import { isAppDeployManifest } from './deploy';
10
+ import { isAppStateSpec } from './isAppStateSpec';
11
+ import { isMediaManifest } from './media';
12
+ import {
13
+ isAppNavigatorManifest,
14
+ isManifestMetadata,
15
+ isScreenRegistry,
16
+ isSplashScreenSpec,
17
+ isThemeConfig,
18
+ } from './screens';
19
+
20
+ /*** Return whether an unknown value satisfies the canonical AppManifest shape. */
21
+ export function isAppManifest(value: unknown): value is AppManifest {
22
+ return (
23
+ isRecord(value) &&
24
+ hasRequiredManifestKeys(value) &&
25
+ !('generatedApis' in value) &&
26
+ isManifestMetadata(value.metadata) &&
27
+ isPresentation(value) &&
28
+ isOptionalCapabilities(value) &&
29
+ isInfraManifest(value.infra) &&
30
+ isAppNavigatorManifest(value.navigator) &&
31
+ isScreenRegistry(value.screens) &&
32
+ isAppSettings(value.settings)
33
+ );
34
+ }
35
+
36
+ /*** Validate the canonical application manifest field policy. */
37
+ function hasRequiredManifestKeys(value: Record<string, unknown>): boolean {
38
+ return Object.entries(APP_MANIFEST_KEY_POLICY).every(
39
+ ([key, policy]) => policy === 'optional' || key in value,
40
+ );
41
+ }
42
+
43
+ /*** Validate the canonical application manifest field policy. */
44
+ function isActiveThemeMode(value: unknown): boolean {
45
+ return value === undefined || value === 'dark' || value === 'light';
46
+ }
47
+
48
+ /*** Validate the canonical application manifest field policy. */
49
+ function isRepositoryManifest(value: unknown): boolean {
50
+ return (
51
+ isRecord(value) &&
52
+ value.provider === 'github' &&
53
+ typeof value.owner === 'string' &&
54
+ value.owner.length > 0 &&
55
+ typeof value.name === 'string' &&
56
+ value.name.length > 0 &&
57
+ typeof value.url === 'string' &&
58
+ value.url.length > 0 &&
59
+ value.defaultBranch === 'main'
60
+ );
61
+ }
62
+
63
+ /*** Validate the canonical application manifest field policy. */
64
+ function isAppSettings(value: unknown): boolean {
65
+ return (
66
+ isRecord(value) &&
67
+ !('apiBaseUrl' in value) &&
68
+ isRecord(value.localization) &&
69
+ typeof value.localization.defaultLocale === 'string' &&
70
+ isStringArray(value.localization.locales)
71
+ );
72
+ }
73
+
74
+ /*** Validate authored appearance as one cohesive manifest concern. */
75
+ function isPresentation(value: Record<string, unknown>): boolean {
76
+ return (
77
+ Array.isArray(value.themes) &&
78
+ value.themes.every(isThemeConfig) &&
79
+ typeof value.activeThemeId === 'string' &&
80
+ isActiveThemeMode(value.activeThemeMode) &&
81
+ (value.splashScreen === undefined || isSplashScreenSpec(value.splashScreen)) &&
82
+ (value.media === undefined || isMediaManifest(value.media))
83
+ );
84
+ }
85
+
86
+ /*** Validate independently optional application capability selections. */
87
+ function isOptionalCapabilities(value: Record<string, unknown>): boolean {
88
+ return (
89
+ (value.deploy === undefined || isAppDeployManifest(value.deploy)) &&
90
+ (value.state === undefined || isAppStateSpec(value.state)) &&
91
+ (value.dataSources === undefined || isDataSourceRegistry(value.dataSources)) &&
92
+ (value.dataBindings === undefined || isComponentDataBindingRegistry(value.dataBindings)) &&
93
+ (value.repository === undefined || isRepositoryManifest(value.repository))
94
+ );
95
+ }
@@ -0,0 +1,13 @@
1
+ import { isRecord } from '@ankhorage/utility/object';
2
+
3
+ import type { AppStateSpec } from '../state';
4
+
5
+ /*** Application state cannot claim persistence unsupported by the selected Legend adapter. */
6
+ export function isAppStateSpec(value: unknown): value is AppStateSpec {
7
+ return (
8
+ isRecord(value) &&
9
+ value.provider === 'legend' &&
10
+ (value.persistence === undefined || value.persistence === false) &&
11
+ Object.keys(value).every((key) => key === 'provider' || key === 'persistence')
12
+ );
13
+ }
@@ -0,0 +1,19 @@
1
+ import { isRecord } from '@ankhorage/utility/object';
2
+
3
+ /*** Validate the existing recursive ManifestValue domain used by authored bindings and API metadata. */
4
+ export function isManifestValue(value: unknown): boolean {
5
+ if (
6
+ value === null ||
7
+ typeof value === 'string' ||
8
+ typeof value === 'number' ||
9
+ typeof value === 'boolean'
10
+ ) {
11
+ return true;
12
+ }
13
+
14
+ if (Array.isArray(value)) {
15
+ return value.every(isManifestValue);
16
+ }
17
+
18
+ return isRecord(value) && Object.values(value).every(isManifestValue);
19
+ }