@highstate/contract 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +238 -0
- package/dist/index.mjs +135 -0
- package/package.json +2 -2
package/dist/index.d.ts
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
import { Static, TUnion, TString, TNumber, TBoolean, TArray, TLiteral, TSchema, TAnySchema, TObject, TOptional } from '@sinclair/typebox';
|
2
|
+
|
3
|
+
type UnitRegistration = Readonly<{
|
4
|
+
type: string;
|
5
|
+
name: string;
|
6
|
+
config: Readonly<Record<string, string>>;
|
7
|
+
dependencies: readonly string[];
|
8
|
+
}>;
|
9
|
+
declare function getUnitRegistrations(): Readonly<Record<string, UnitRegistration>>;
|
10
|
+
|
11
|
+
/**
|
12
|
+
* The schema for a single argument value.
|
13
|
+
*
|
14
|
+
* This argument can have a limited set of types: primitive types, arrays of strings or numbers.
|
15
|
+
* This limitation is due to the fact that we need to display the arguments in the UI, and we can't display more complex types.
|
16
|
+
* Moreover, it encourages using separate components for organizing complex data.
|
17
|
+
*/
|
18
|
+
declare const argumentValueSchema: TUnion<[TString, TNumber, TBoolean, TArray<TString>, TArray<TNumber>]>;
|
19
|
+
type ArgumentValueSchema = typeof argumentValueSchema;
|
20
|
+
type ArgumentValue = Static<ArgumentValueSchema>;
|
21
|
+
type AllowedArgumentSchema = TString | TNumber | TBoolean | TArray<TString> | TArray<TNumber> | TUnion<TLiteral[]>;
|
22
|
+
/**
|
23
|
+
* The generic metadata of some contract.
|
24
|
+
*/
|
25
|
+
type Meta = {
|
26
|
+
/**
|
27
|
+
* The display name of the entity which can be shown in the UI.
|
28
|
+
*/
|
29
|
+
displayName?: string;
|
30
|
+
/**
|
31
|
+
* The description of the entity which can be shown in the UI.
|
32
|
+
*/
|
33
|
+
description?: string;
|
34
|
+
/**
|
35
|
+
* The hex color of the entity which can be used in the UI.
|
36
|
+
*
|
37
|
+
* @example "#ff0000"
|
38
|
+
*/
|
39
|
+
color?: string;
|
40
|
+
};
|
41
|
+
|
42
|
+
type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
43
|
+
type ListRequiredKeys<T extends Record<string, unknown>> = T extends Record<string, never> ? never : {
|
44
|
+
[K in keyof T]-?: undefined extends T[K] ? never : K;
|
45
|
+
}[keyof T];
|
46
|
+
type PickOptionalRecords<T extends Record<string, Record<string, unknown>>> = {
|
47
|
+
[K in keyof T]: ListRequiredKeys<T[K]> extends never ? K : never;
|
48
|
+
}[keyof T];
|
49
|
+
type PickRequiredRecords<T extends Record<string, Record<string, unknown>>> = {
|
50
|
+
[K in keyof T]: ListRequiredKeys<T[K]> extends never ? never : K;
|
51
|
+
}[keyof T];
|
52
|
+
type OptionalEmptyRecords<T extends Record<string, Record<string, unknown>>> = {
|
53
|
+
[K in PickOptionalRecords<T>]?: T[K];
|
54
|
+
} & {
|
55
|
+
[K in PickRequiredRecords<T>]: T[K];
|
56
|
+
};
|
57
|
+
type PickUndefinedKeys<T extends Record<string, unknown>> = {
|
58
|
+
[K in keyof T]: undefined extends T[K] ? K : never;
|
59
|
+
}[keyof T];
|
60
|
+
type OptionalUndefinedFields<T extends Record<string, unknown>> = {
|
61
|
+
[K in PickUndefinedKeys<T>]?: T[K];
|
62
|
+
} & {
|
63
|
+
[K in Exclude<keyof T, PickUndefinedKeys<T>>]: T[K];
|
64
|
+
};
|
65
|
+
/**
|
66
|
+
* Removes the indentation from a multiline string.
|
67
|
+
*
|
68
|
+
* @param str The string to trim.
|
69
|
+
* @returns The trimmed string.
|
70
|
+
*/
|
71
|
+
declare function text(array: TemplateStringsArray, ...values: unknown[]): string;
|
72
|
+
|
73
|
+
/**
|
74
|
+
* The entity is some abstract object which can be passed from one component to another through their inputs and outputs.
|
75
|
+
* Every entity must have a type.
|
76
|
+
* Every component inputs and outputs will reference such types and only entities of the same type can be passed.
|
77
|
+
*/
|
78
|
+
type Entity<TType extends string = string, TEntitySchema extends TSchema = TSchema> = {
|
79
|
+
/**
|
80
|
+
* The static type of the entity.
|
81
|
+
*/
|
82
|
+
type: TType;
|
83
|
+
/**
|
84
|
+
* The JSON schema of the entity value.
|
85
|
+
*/
|
86
|
+
schema: TEntitySchema;
|
87
|
+
/**
|
88
|
+
* Whether the content of the entity is sensitive and should be hidden from the UI.
|
89
|
+
*/
|
90
|
+
sensitive: boolean;
|
91
|
+
/**
|
92
|
+
* The extra metadata of the entity.
|
93
|
+
*/
|
94
|
+
meta: Meta;
|
95
|
+
};
|
96
|
+
type EntityOptions<TType extends string, TSchema extends TAnySchema> = PartialKeys<Entity<TType, TSchema>, "sensitive" | "meta">;
|
97
|
+
declare function defineEntity<TType extends string, TSchema extends TAnySchema>(options: EntityOptions<TType, TSchema>): Entity<TType, TSchema>;
|
98
|
+
declare function isEntity(value: unknown): value is Entity;
|
99
|
+
type OutputRef<TType extends string = string> = {
|
100
|
+
type: TType;
|
101
|
+
project: string;
|
102
|
+
stack: string;
|
103
|
+
output: string;
|
104
|
+
};
|
105
|
+
|
106
|
+
type ComponentArgument = {
|
107
|
+
schema: ArgumentValueSchema;
|
108
|
+
required: boolean;
|
109
|
+
meta: Meta;
|
110
|
+
};
|
111
|
+
type ComponentArgumentFullOptions = Meta & {
|
112
|
+
schema: AllowedArgumentSchema;
|
113
|
+
required?: boolean;
|
114
|
+
};
|
115
|
+
type ComponentArgumentOptions = AllowedArgumentSchema | ComponentArgumentFullOptions;
|
116
|
+
type ComponentArgumentOptionsToSchema<T extends ComponentArgumentOptions> = T extends TSchema ? T : T["required"] extends false ? TOptional<T["schema"]> : T["schema"];
|
117
|
+
type ComponentArgumentMapToValue<T extends Record<string, ComponentArgumentOptions>> = {
|
118
|
+
[K in keyof T]: Static<ComponentArgumentOptionsToSchema<T[K]>>;
|
119
|
+
};
|
120
|
+
type ComponentInput = {
|
121
|
+
type: string;
|
122
|
+
required: boolean;
|
123
|
+
multiple: boolean;
|
124
|
+
meta: Meta;
|
125
|
+
};
|
126
|
+
type ComponentInputFullOptions = Meta & {
|
127
|
+
entity: Entity;
|
128
|
+
required?: boolean;
|
129
|
+
multiple?: boolean;
|
130
|
+
};
|
131
|
+
type ComponentInputOptions = Entity | ComponentInputFullOptions;
|
132
|
+
type ComponentInputOptionsToOutputRef<T extends ComponentInputOptions> = T extends Entity ? OutputRef<T["type"]> : T extends ComponentInputFullOptions ? T["required"] extends false ? T["multiple"] extends true ? OutputRef<T["entity"]["type"]>[] | undefined : OutputRef<T["entity"]["type"]> | undefined : T["multiple"] extends true ? OutputRef<T["entity"]["type"]>[] : OutputRef<T["entity"]["type"]> : never;
|
133
|
+
type ComponentInputSpec = [entity: Entity, required: boolean, multiple: boolean];
|
134
|
+
type ComponentInputOptionsToSpec<T extends ComponentInputOptions> = T extends Entity ? [T, true, false] : T extends ComponentInputFullOptions ? T["required"] extends false ? T["multiple"] extends true ? [T["entity"], false, true] : [T["entity"], false, false] : T["multiple"] extends true ? [T["entity"], true, true] : [T["entity"], true, false] : never;
|
135
|
+
type ComponentInputMapToValue<T extends Record<string, ComponentInputOptions>> = OptionalUndefinedFields<{
|
136
|
+
[K in keyof T]: ComponentInputOptionsToOutputRef<T[K]>;
|
137
|
+
}>;
|
138
|
+
type ComponentParams<TArgs extends Record<string, ComponentArgumentOptions>, TInputs extends Record<string, ComponentInputOptions>> = {
|
139
|
+
name: string;
|
140
|
+
args: ComponentArgumentMapToValue<TArgs>;
|
141
|
+
inputs: ComponentInputMapToValue<TInputs>;
|
142
|
+
};
|
143
|
+
type InputComponentParams<TArgs extends Record<string, ArgumentValue>, TInputs extends Record<string, unknown>> = {
|
144
|
+
name: string;
|
145
|
+
} & OptionalEmptyRecords<{
|
146
|
+
args: TArgs;
|
147
|
+
inputs: TInputs;
|
148
|
+
}>;
|
149
|
+
type ComponentOptions<TArgs extends Record<string, ComponentArgumentOptions>, TInputs extends Record<string, ComponentInputOptions>, TOutputs extends Record<string, ComponentInputOptions>> = {
|
150
|
+
type: string;
|
151
|
+
meta?: ComponentMeta;
|
152
|
+
args?: TArgs;
|
153
|
+
inputs?: TInputs;
|
154
|
+
outputs?: TOutputs;
|
155
|
+
create: (params: ComponentParams<TArgs, TInputs>) => ComponentInputMapToValue<TOutputs>;
|
156
|
+
};
|
157
|
+
type ComponentMeta = Meta & {
|
158
|
+
primaryIcon?: string;
|
159
|
+
primaryIconColor?: string;
|
160
|
+
secondaryIcon?: string;
|
161
|
+
secondaryIconColor?: string;
|
162
|
+
category?: string;
|
163
|
+
};
|
164
|
+
type ComponentModel = {
|
165
|
+
/**
|
166
|
+
* The type of the component.
|
167
|
+
*/
|
168
|
+
type: string;
|
169
|
+
/**
|
170
|
+
* The record of the argument schemas.
|
171
|
+
*/
|
172
|
+
args: Record<string, ComponentArgument>;
|
173
|
+
/**
|
174
|
+
* The record of the input schemas.
|
175
|
+
*/
|
176
|
+
inputs: Record<string, ComponentInput>;
|
177
|
+
/**
|
178
|
+
* The record of the output schemas.
|
179
|
+
*/
|
180
|
+
outputs: Record<string, ComponentInput>;
|
181
|
+
/**
|
182
|
+
* The extra metadata of the component.
|
183
|
+
*/
|
184
|
+
meta: ComponentMeta;
|
185
|
+
};
|
186
|
+
type InputSpecToOutputRef<T extends ComponentInputSpec> = T[1] extends true ? T[2] extends true ? OutputRef<T[0]["type"]>[] : OutputRef<T[0]["type"]> : T[2] extends true ? OutputRef<T[0]["type"]>[] | undefined : OutputRef<T[0]["type"]> | undefined;
|
187
|
+
type OutputRefMap<TInputs extends Record<string, ComponentInputSpec>> = TInputs extends Record<string, [string, never, never]> ? Record<string, never> : {
|
188
|
+
[K in keyof TInputs]: InputSpecToOutputRef<TInputs[K]>;
|
189
|
+
};
|
190
|
+
type Component<TArgs extends Record<string, ArgumentValue> = Record<string, never>, TInputs extends Record<string, ComponentInputSpec> = Record<string, never>, TOutputs extends Record<string, ComponentInputSpec> = Record<string, never>> = {
|
191
|
+
/**
|
192
|
+
* The non-generic model of the component.
|
193
|
+
*/
|
194
|
+
model: ComponentModel;
|
195
|
+
/**
|
196
|
+
* Creates the component at the evaluation time.
|
197
|
+
*/
|
198
|
+
(context: InputComponentParams<TArgs, OutputRefMap<TInputs>>): OutputRefMap<TOutputs>;
|
199
|
+
};
|
200
|
+
type ArgumentOptionsMapToStatic<T extends Record<string, ComponentArgumentOptions>> = T extends Record<string, never> ? Record<string, never> : Static<TObject<{
|
201
|
+
[K in keyof T]: ComponentArgumentOptionsToSchema<T[K]>;
|
202
|
+
}>>;
|
203
|
+
declare function defineComponent<TArgs extends Record<string, ComponentArgumentOptions> = Record<string, never>, TInputs extends Record<string, ComponentInputOptions> = Record<string, never>, TOutputs extends Record<string, ComponentInputOptions> = Record<string, never>>(options: ComponentOptions<TArgs, TInputs, TOutputs>): Component<ArgumentOptionsMapToStatic<TArgs>, {
|
204
|
+
[K in keyof TInputs]: ComponentInputOptionsToSpec<TInputs[K]>;
|
205
|
+
}, {
|
206
|
+
[K in keyof TOutputs]: ComponentInputOptionsToSpec<TOutputs[K]>;
|
207
|
+
}>;
|
208
|
+
declare function isComponent(value: unknown): value is Component;
|
209
|
+
|
210
|
+
type UnitOptions<TArgs extends Record<string, ComponentArgumentOptions>, TInputs extends Record<string, ComponentInputOptions>, TOutputs extends Record<string, ComponentInputOptions>, TSecrets extends Record<string, ComponentArgumentOptions>> = Omit<ComponentOptions<TArgs, TInputs, TOutputs>, "create"> & {
|
211
|
+
source: UnitSource;
|
212
|
+
secrets?: TSecrets;
|
213
|
+
};
|
214
|
+
type UnitSource = {
|
215
|
+
type: "npm";
|
216
|
+
package: string;
|
217
|
+
version?: string;
|
218
|
+
path?: string;
|
219
|
+
};
|
220
|
+
type UnitModel = ComponentModel & {
|
221
|
+
source: UnitSource;
|
222
|
+
/**
|
223
|
+
* The record of the secret argument schemas.
|
224
|
+
*/
|
225
|
+
secrets: Record<string, ComponentArgument>;
|
226
|
+
};
|
227
|
+
type Unit<TArgs extends Record<string, ArgumentValue> = Record<string, never>, TInputs extends Record<string, ComponentInputSpec> = Record<string, never>, TOutputs extends Record<string, ComponentInputSpec> = Record<string, never>, TSecrets extends Record<string, ArgumentValue> = Record<string, never>> = Component<TArgs, TInputs, TOutputs> & {
|
228
|
+
__secrets: TSecrets;
|
229
|
+
model: UnitModel;
|
230
|
+
};
|
231
|
+
declare function isUnitModel(model: ComponentModel): model is UnitModel;
|
232
|
+
declare function defineUnit<TArgs extends Record<string, ComponentArgumentOptions> = Record<string, never>, TInputs extends Record<string, ComponentInputOptions> = Record<string, never>, TOutputs extends Record<string, ComponentInputOptions> = Record<string, never>, TSecrets extends Record<string, ComponentArgumentOptions> = Record<string, never>>(options: UnitOptions<TArgs, TInputs, TOutputs, TSecrets>): Unit<ArgumentOptionsMapToStatic<TArgs>, {
|
233
|
+
[K in keyof TInputs]: ComponentInputOptionsToSpec<TInputs[K]>;
|
234
|
+
}, {
|
235
|
+
[K in keyof TOutputs]: ComponentInputOptionsToSpec<TOutputs[K]>;
|
236
|
+
}, ArgumentOptionsMapToStatic<TSecrets>>;
|
237
|
+
|
238
|
+
export { type ArgumentValue, type Component, type ComponentArgument, type ComponentInput, type ComponentInputSpec, type ComponentMeta, type ComponentModel, type Entity, type OutputRef, type Unit, type UnitModel, type UnitRegistration, type UnitSource, defineComponent, defineEntity, defineUnit, getUnitRegistrations, isComponent, isEntity, isUnitModel, text };
|
package/dist/index.mjs
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
import { OptionalKind, Type } from '@sinclair/typebox';
|
2
|
+
import { mapValues } from 'remeda';
|
3
|
+
|
4
|
+
const unitRegistrations = {};
|
5
|
+
function getUnitRegistrations() {
|
6
|
+
return unitRegistrations;
|
7
|
+
}
|
8
|
+
function registerUnit(unit) {
|
9
|
+
unitRegistrations[`${unit.type}.${unit.name}`] = unit;
|
10
|
+
}
|
11
|
+
|
12
|
+
function defineEntity(options) {
|
13
|
+
return {
|
14
|
+
sensitive: false,
|
15
|
+
meta: {},
|
16
|
+
...options
|
17
|
+
};
|
18
|
+
}
|
19
|
+
function isEntity(value) {
|
20
|
+
return typeof value === "object" && value !== null && "type" in value && "schema" in value && "sensitive" in value && "meta" in value;
|
21
|
+
}
|
22
|
+
|
23
|
+
function defineComponent(options) {
|
24
|
+
function create(params) {
|
25
|
+
const { name, args, inputs } = params;
|
26
|
+
return options.create({
|
27
|
+
name,
|
28
|
+
args: args ?? {},
|
29
|
+
inputs: inputs ?? {}
|
30
|
+
});
|
31
|
+
}
|
32
|
+
create.model = {
|
33
|
+
type: options.type,
|
34
|
+
args: mapValues(options.args ?? {}, mapArgument),
|
35
|
+
inputs: mapValues(options.inputs ?? {}, mapInput),
|
36
|
+
outputs: mapValues(options.outputs ?? {}, mapInput),
|
37
|
+
meta: options.meta ?? {}
|
38
|
+
};
|
39
|
+
return create;
|
40
|
+
}
|
41
|
+
function isComponent(value) {
|
42
|
+
return typeof value === "function" && "model" in value;
|
43
|
+
}
|
44
|
+
function mapArgument(value) {
|
45
|
+
if ("schema" in value) {
|
46
|
+
return {
|
47
|
+
schema: value.schema,
|
48
|
+
required: value.required ?? !value.schema[OptionalKind],
|
49
|
+
meta: {
|
50
|
+
displayName: value.displayName,
|
51
|
+
description: value.description,
|
52
|
+
color: value.color
|
53
|
+
}
|
54
|
+
};
|
55
|
+
}
|
56
|
+
return {
|
57
|
+
schema: value,
|
58
|
+
required: !value[OptionalKind],
|
59
|
+
secret: false,
|
60
|
+
meta: {}
|
61
|
+
};
|
62
|
+
}
|
63
|
+
function mapInput(value) {
|
64
|
+
if ("entity" in value) {
|
65
|
+
return {
|
66
|
+
type: value.entity.type,
|
67
|
+
required: value.required ?? true,
|
68
|
+
multiple: value.multiple ?? false,
|
69
|
+
meta: {
|
70
|
+
displayName: value.displayName,
|
71
|
+
description: value.description,
|
72
|
+
color: value.color
|
73
|
+
}
|
74
|
+
};
|
75
|
+
}
|
76
|
+
return {
|
77
|
+
type: value.type,
|
78
|
+
required: true,
|
79
|
+
multiple: false,
|
80
|
+
meta: {}
|
81
|
+
};
|
82
|
+
}
|
83
|
+
|
84
|
+
function isUnitModel(model) {
|
85
|
+
return "source" in model;
|
86
|
+
}
|
87
|
+
function defineUnit(options) {
|
88
|
+
const component = defineComponent({
|
89
|
+
...options,
|
90
|
+
create({ name, args, inputs }) {
|
91
|
+
registerUnit({
|
92
|
+
type: options.type,
|
93
|
+
name,
|
94
|
+
config: {
|
95
|
+
...mapValues(args, (value) => typeof value === "string" ? value : JSON.stringify(value)),
|
96
|
+
...mapValues(inputs, (value) => JSON.stringify(value))
|
97
|
+
},
|
98
|
+
dependencies: Object.values(inputs).map((value) => `${value.project}.${value.stack}`)
|
99
|
+
});
|
100
|
+
return fillUnitOutputs(name, options.type, options.outputs);
|
101
|
+
}
|
102
|
+
});
|
103
|
+
component.model.source = options.source;
|
104
|
+
component.model.secrets = mapValues(options.secrets ?? {}, mapArgument);
|
105
|
+
return component;
|
106
|
+
}
|
107
|
+
function fillUnitOutputs(name, type, optionsOutputs = {}) {
|
108
|
+
const outputs = {};
|
109
|
+
for (const key in optionsOutputs) {
|
110
|
+
outputs[key] = {
|
111
|
+
type,
|
112
|
+
project: type,
|
113
|
+
stack: name,
|
114
|
+
output: key
|
115
|
+
};
|
116
|
+
}
|
117
|
+
return outputs;
|
118
|
+
}
|
119
|
+
|
120
|
+
function text(array, ...values) {
|
121
|
+
const str = array.reduce((result, part, i) => result + part + (String(values[i]) || ""), "");
|
122
|
+
const lines = str.split("\n");
|
123
|
+
const indent = lines.filter((line) => line.trim() !== "").map((line) => line.match(/^\s*/)?.[0].length ?? 0).reduce((min, indent2) => Math.min(min, indent2), Infinity);
|
124
|
+
return lines.map((line) => line.slice(indent)).join("\n").trim();
|
125
|
+
}
|
126
|
+
|
127
|
+
Type.Union([
|
128
|
+
Type.String(),
|
129
|
+
Type.Number(),
|
130
|
+
Type.Boolean(),
|
131
|
+
Type.Array(Type.String()),
|
132
|
+
Type.Array(Type.Number())
|
133
|
+
]);
|
134
|
+
|
135
|
+
export { defineComponent, defineEntity, defineUnit, getUnitRegistrations, isComponent, isEntity, isUnitModel, text };
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@highstate/contract",
|
3
|
-
"version": "0.2.
|
3
|
+
"version": "0.2.1",
|
4
4
|
"type": "module",
|
5
5
|
"module": "dist/index.mjs",
|
6
6
|
"types": "dist/index.d.ts",
|
@@ -28,5 +28,5 @@
|
|
28
28
|
"jest": "^29.7.0",
|
29
29
|
"pkgroll": "^2.5.1"
|
30
30
|
},
|
31
|
-
"gitHead": "
|
31
|
+
"gitHead": "205bae57e7b9e8e8ebe979859df3f18fdb8cfe81"
|
32
32
|
}
|