@ankhorage/contracts 25.2.0 → 26.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/README.md +1 -1
- package/dist/appManifest/bindings.d.ts +3 -3
- package/dist/appManifest/bindings.d.ts.map +1 -1
- package/dist/appManifest/bindings.js +46 -65
- package/dist/appManifest/bindings.js.map +1 -1
- package/dist/appManifest/screens.js +2 -2
- package/dist/appManifest/screens.js.map +1 -1
- package/dist/bindings.d.ts +39 -64
- package/dist/bindings.d.ts.map +1 -1
- package/dist/bindings.js.map +1 -1
- package/dist/structure/generated.d.ts +2 -2
- package/dist/structure/generated.js +2 -2
- package/dist/structure/generated.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/src/appManifest/bindings.ts +46 -72
- package/src/appManifest/screens.ts +2 -2
- package/src/appManifest.test.ts +7 -8
- package/src/bindings.test.ts +86 -516
- package/src/bindings.ts +41 -88
- package/src/contracts.test.ts +10 -20
- package/src/structure/generated.ts +2 -2
- package/src/types.ts +2 -2
package/src/bindings.ts
CHANGED
|
@@ -1,123 +1,76 @@
|
|
|
1
|
+
import type { Capability } from './capability';
|
|
1
2
|
import type { EntityRegistry, ValueMap } from './collections';
|
|
2
|
-
import type { ApiId, EndpointId, OperationId } from './data';
|
|
3
3
|
import type { SerializableValue } from './serializable';
|
|
4
4
|
|
|
5
5
|
export type ComponentInstanceId = string;
|
|
6
6
|
export type ComponentTypeId = string;
|
|
7
|
-
|
|
8
7
|
export type BindingValue = SerializableValue;
|
|
9
|
-
|
|
10
8
|
export type BindingDataPath = string;
|
|
11
|
-
|
|
12
9
|
export type BindingValueTransform = 'lowercase' | 'trim' | 'uppercase';
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
readonly
|
|
17
|
-
readonly
|
|
11
|
+
/** A portable reference to a readable capability value or a cached invocation result. */
|
|
12
|
+
export interface BindingCapabilityReference {
|
|
13
|
+
readonly capability: Capability['id'];
|
|
14
|
+
readonly path?: BindingDataPath;
|
|
15
|
+
readonly result?: string;
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
|
30
|
-
|
|
31
|
-
readonly value: BindingValue;
|
|
32
|
-
}
|
|
18
|
+
/** A portable request to invoke a capability and optionally retain its result in a local slot. */
|
|
19
|
+
export interface BindingInvocation {
|
|
20
|
+
readonly capability: Capability['id'];
|
|
21
|
+
readonly input?: BindingInputMap;
|
|
22
|
+
readonly result?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** A recursive, serializable value expression used by bindings and invocation inputs. */
|
|
26
|
+
export type BindingExpression =
|
|
27
|
+
| BindingCapabilityReference
|
|
28
|
+
| { readonly kind: 'array'; readonly items: readonly BindingExpression[] }
|
|
33
29
|
| {
|
|
34
|
-
readonly kind: '
|
|
35
|
-
readonly
|
|
36
|
-
readonly
|
|
30
|
+
readonly kind: 'fallback';
|
|
31
|
+
readonly value: BindingExpression;
|
|
32
|
+
readonly fallback: BindingExpression;
|
|
37
33
|
}
|
|
34
|
+
| { readonly kind: 'literal'; readonly value: BindingValue }
|
|
35
|
+
| { readonly kind: 'object'; readonly fields: ValueMap<string, BindingExpression> }
|
|
38
36
|
| {
|
|
39
|
-
readonly kind: '
|
|
40
|
-
readonly
|
|
37
|
+
readonly kind: 'transform';
|
|
38
|
+
readonly value: BindingExpression;
|
|
39
|
+
readonly transforms: readonly BindingValueTransform[];
|
|
41
40
|
};
|
|
42
41
|
|
|
43
|
-
export
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
42
|
+
export type BindingInputValue = BindingExpression;
|
|
43
|
+
export type BindingInputMap = ValueMap<string, BindingInputValue>;
|
|
44
|
+
export type BindingConditionOperator = 'eq' | 'exists' | 'neq' | 'notExists';
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
readonly source
|
|
46
|
+
/** A condition evaluated from portable binding expressions. */
|
|
47
|
+
export interface BindingCondition {
|
|
48
|
+
readonly source: BindingExpression;
|
|
49
|
+
readonly operator: BindingConditionOperator;
|
|
50
|
+
readonly value?: BindingExpression;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
/** A lifecycle-specific expression rendered when a bound value reaches one state. */
|
|
55
54
|
export interface BindingLifecycleBehavior {
|
|
56
55
|
readonly state: BindingLifecycleState;
|
|
57
|
-
readonly
|
|
56
|
+
readonly value?: BindingExpression;
|
|
58
57
|
readonly message?: string;
|
|
59
58
|
}
|
|
60
59
|
|
|
60
|
+
export type BindingLifecycleState = 'empty' | 'error' | 'loading';
|
|
61
|
+
|
|
61
62
|
export interface PropBinding {
|
|
62
|
-
readonly
|
|
63
|
-
readonly fallback?: BindingFallback;
|
|
63
|
+
readonly value: BindingExpression;
|
|
64
64
|
readonly loading?: BindingLifecycleBehavior;
|
|
65
65
|
readonly error?: BindingLifecycleBehavior;
|
|
66
66
|
readonly empty?: BindingLifecycleBehavior;
|
|
67
|
-
readonly transforms?: readonly BindingValueTransform[];
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
readonly kind: 'array';
|
|
73
|
-
readonly items: readonly BindingInputValue[];
|
|
74
|
-
}
|
|
75
|
-
| {
|
|
76
|
-
readonly kind: 'literal';
|
|
77
|
-
readonly value: BindingValue;
|
|
78
|
-
}
|
|
79
|
-
| {
|
|
80
|
-
readonly kind: 'object';
|
|
81
|
-
readonly fields: ValueMap<string, BindingInputValue>;
|
|
82
|
-
}
|
|
83
|
-
| {
|
|
84
|
-
readonly kind: 'source';
|
|
85
|
-
readonly source: BindingValueSource;
|
|
86
|
-
readonly transforms?: readonly BindingValueTransform[];
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export type BindingInputMap = ValueMap<string, BindingInputValue>;
|
|
90
|
-
|
|
91
|
-
export interface OperationScreenDataLoaderDefinition {
|
|
92
|
-
readonly kind: 'operation';
|
|
93
|
-
readonly id?: string;
|
|
94
|
-
readonly operation: BindingOperationRef;
|
|
95
|
-
readonly input?: BindingInputMap;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export type ScreenDataLoaderDefinition = OperationScreenDataLoaderDefinition;
|
|
99
|
-
|
|
100
|
-
export type BindingConditionOperator = 'eq' | 'exists' | 'neq' | 'notExists';
|
|
101
|
-
|
|
102
|
-
export interface BindingCondition {
|
|
103
|
-
readonly source: BindingValueSource;
|
|
104
|
-
readonly operator: BindingConditionOperator;
|
|
105
|
-
readonly value?: BindingValue;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export type EventBindingTarget =
|
|
109
|
-
| {
|
|
110
|
-
readonly kind: 'action';
|
|
111
|
-
readonly type: string;
|
|
112
|
-
}
|
|
113
|
-
| {
|
|
114
|
-
readonly kind: 'operation';
|
|
115
|
-
readonly operation: BindingOperationRef;
|
|
116
|
-
};
|
|
69
|
+
/** A screen loader is one capability invocation, optionally storing its result by slot name. */
|
|
70
|
+
export type ScreenDataLoaderDefinition = BindingInvocation;
|
|
117
71
|
|
|
118
72
|
export interface EventBinding {
|
|
119
|
-
readonly target:
|
|
120
|
-
readonly input?: BindingInputMap;
|
|
73
|
+
readonly target: BindingInvocation;
|
|
121
74
|
readonly when?: BindingCondition;
|
|
122
75
|
}
|
|
123
76
|
|
package/src/contracts.test.ts
CHANGED
|
@@ -219,7 +219,7 @@ describe('contracts', () => {
|
|
|
219
219
|
expect(theme.recipes?.patterns?.Panel?.padding).toBe('xl');
|
|
220
220
|
});
|
|
221
221
|
|
|
222
|
-
it('accepts screens with
|
|
222
|
+
it('accepts screens with capability loaders and repeat empty-state nodes', () => {
|
|
223
223
|
const manifest: Pick<AppManifest, 'screens'> = {
|
|
224
224
|
screens: {
|
|
225
225
|
products: {
|
|
@@ -230,12 +230,8 @@ describe('contracts', () => {
|
|
|
230
230
|
type: 'Grid',
|
|
231
231
|
repeat: {
|
|
232
232
|
source: {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
dataSourceId: 'nutrition-api',
|
|
236
|
-
endpointId: 'products',
|
|
237
|
-
operationId: 'nutrition.products.list',
|
|
238
|
-
},
|
|
233
|
+
capability: 'api.nutrition.productsList',
|
|
234
|
+
result: 'products',
|
|
239
235
|
path: 'products',
|
|
240
236
|
},
|
|
241
237
|
empty: [
|
|
@@ -252,20 +248,12 @@ describe('contracts', () => {
|
|
|
252
248
|
},
|
|
253
249
|
dataLoaders: [
|
|
254
250
|
{
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
operation: {
|
|
258
|
-
dataSourceId: 'nutrition-api',
|
|
259
|
-
endpointId: 'products',
|
|
260
|
-
operationId: 'nutrition.products.getById',
|
|
261
|
-
},
|
|
251
|
+
capability: 'api.nutrition.productsGetById',
|
|
252
|
+
result: 'product',
|
|
262
253
|
input: {
|
|
263
254
|
id: {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
kind: 'context',
|
|
267
|
-
path: 'route.params.id',
|
|
268
|
-
},
|
|
255
|
+
capability: 'context.route',
|
|
256
|
+
path: 'params.id',
|
|
269
257
|
},
|
|
270
258
|
},
|
|
271
259
|
},
|
|
@@ -275,7 +263,9 @@ describe('contracts', () => {
|
|
|
275
263
|
};
|
|
276
264
|
|
|
277
265
|
expect(JSON.parse(JSON.stringify(manifest))).toEqual(manifest);
|
|
278
|
-
expect(manifest.screens.products?.dataLoaders?.[0]?.
|
|
266
|
+
expect(manifest.screens.products?.dataLoaders?.[0]?.capability).toBe(
|
|
267
|
+
'api.nutrition.productsGetById',
|
|
268
|
+
);
|
|
279
269
|
expect(manifest.screens.products?.root.repeat?.empty?.[0]?.type).toBe('Notice');
|
|
280
270
|
});
|
|
281
271
|
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import type { StructureDescriptorDocument } from '@ankhorage/contracts/structure';
|
|
3
3
|
|
|
4
4
|
export const STRUCTURE_DESCRIPTOR_COMPILER_VERSION = '6.0.3';
|
|
5
|
-
export const STRUCTURE_DESCRIPTOR_FINGERPRINT = 'sha256:
|
|
5
|
+
export const STRUCTURE_DESCRIPTOR_FINGERPRINT = 'sha256:535fb077e79daec8b09c756ed220bd7cb29bdf62d53559e3032ca246dd3f5bd3';
|
|
6
6
|
|
|
7
7
|
export const STRUCTURE_DESCRIPTOR = {
|
|
8
8
|
"protocolVersion": 1,
|
|
9
9
|
"packageName": "@ankhorage/contracts",
|
|
10
|
-
"packageVersion": "
|
|
10
|
+
"packageVersion": "26.0.0",
|
|
11
11
|
"roots": {
|
|
12
12
|
"auth-flow": "AuthFlowConfig",
|
|
13
13
|
"auth-profile": "AuthProfileSpec",
|
package/src/types.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ColorHarmony } from '@ankhorage/color-theory';
|
|
|
2
2
|
|
|
3
3
|
import type { AuthIdentifierKind, AuthSignUpField } from './auth';
|
|
4
4
|
import type {
|
|
5
|
-
|
|
5
|
+
BindingExpression,
|
|
6
6
|
ComponentDataBindingRegistry,
|
|
7
7
|
ScreenDataLoaderDefinition,
|
|
8
8
|
} from './bindings';
|
|
@@ -153,7 +153,7 @@ export interface SvgIconSpec extends IconPresentationSpec {
|
|
|
153
153
|
export type IconSpec = NamedIconSpec | SvgIconSpec;
|
|
154
154
|
|
|
155
155
|
export interface UiNodeRepeatSpec {
|
|
156
|
-
source:
|
|
156
|
+
source: BindingExpression;
|
|
157
157
|
itemAlias?: string;
|
|
158
158
|
keyPath?: string;
|
|
159
159
|
empty?: readonly UiNode[];
|