@highstate/pulumi 0.4.1 → 0.4.2

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 CHANGED
@@ -20,9 +20,11 @@ type InputOrArray<T> = Input<T> | InputArray<T> | undefined;
20
20
  /**
21
21
  * The input of inputs of inputs of inputs, so you got the idea.
22
22
  */
23
- type DeepInput<T> = T extends Record<string, unknown> ? Input<{
23
+ type DeepInput<T> = [T] extends [Record<string, unknown> | undefined] ? [T] extends [infer U | undefined] ? Input<{
24
+ [K in keyof U]: DeepInput<U[K]>;
25
+ } | undefined> : Input<{
24
26
  [K in keyof T]: DeepInput<T[K]>;
25
- }> : T extends Array<unknown> ? Input<DeepInput<T[number]>[]> : T extends infer U | undefined ? Input<U | undefined> | undefined : Input<T>;
27
+ }> : [T] extends [Array<unknown> | undefined] ? [T] extends [(infer U)[] | undefined] ? Input<DeepInput<U>[] | undefined> : Input<DeepInput<T>[]> : Input<T>;
26
28
  /**
27
29
  * Merges the given array of `InputOrArray` values into a single flat output array.
28
30
  *
@@ -60,19 +62,46 @@ declare function toPromise<T>(output: Output<T>): Promise<T>;
60
62
  declare function singleton<T>(factory: () => T): () => T;
61
63
  declare function namedSingleton<T>(factory: (name: string) => T): (name: string) => T;
62
64
 
65
+ type Representation = {
66
+ content: string;
67
+ contentType?: string;
68
+ showQRCode?: boolean;
69
+ fileName?: string;
70
+ };
71
+ type TerminalFactory = {
72
+ image: string;
73
+ command: string[];
74
+ cwd?: string;
75
+ env?: Record<string, string>;
76
+ files?: Record<string, string>;
77
+ };
78
+ type StatusField = {
79
+ value: string;
80
+ displayName?: string;
81
+ };
82
+ type ExtraOutputs = {
83
+ $status?: Record<string, StatusField>;
84
+ $representation?: Representation;
85
+ $terminal?: TerminalFactory;
86
+ };
87
+ type OutputMapToDeepInputMap<T extends Record<string, unknown>> = T extends Record<string, never> ? DeepInput<ExtraOutputs> : {
88
+ [K in keyof T]: DeepInput<T[K]>;
89
+ } & DeepInput<ExtraOutputs>;
63
90
  interface UnitContext<TArgs extends Record<string, ArgumentValue>, TInputs extends Record<string, unknown>, TOutputs extends Record<string, unknown>, TSecrets extends Record<string, ArgumentValue>> {
64
91
  args: TArgs;
65
92
  name: string;
66
93
  secrets: Output<TSecrets>;
67
94
  inputs: Output<TInputs>;
68
- outputs(this: void, outputs: DeepInput<TOutputs>): Output<TOutputs>;
95
+ outputs(this: void, outputs: OutputMapToDeepInputMap<TOutputs>): Promise<unknown>;
69
96
  }
70
- type InputSpecToValue<T extends ComponentInputSpec> = T[2] extends true ? Static<T[0]["schema"]>[] : Static<T[0]["schema"]>;
71
- declare function forUnit<TArgs extends Record<string, ArgumentValue>, TInputs extends Record<string, ComponentInputSpec>, TOutputs extends Record<string, ComponentInputSpec>, TSecrets extends Record<string, ArgumentValue>>(unit: Unit<TArgs, TInputs, TOutputs, TSecrets>): UnitContext<TArgs, {
72
- [K in keyof TInputs]: InputSpecToValue<TInputs[K]>;
73
- }, {
74
- [K in keyof TOutputs]: InputSpecToValue<TOutputs[K]>;
75
- }, TSecrets>;
76
- type EntityInput<T extends Entity> = Output<Static<T["schema"]>>;
97
+ type InputSpecToValue<T extends ComponentInputSpec> = T[2] extends true ? Static<T[0]["schema"]>[] : T[1] extends true ? Static<T[0]["schema"]> : Static<T[0]["schema"]> | undefined;
98
+ type InputSpecMapToValueMap<T extends Record<string, ComponentInputSpec>> = T extends Record<string, never> ? Record<string, never> : {
99
+ [K in keyof T]: InputSpecToValue<T[K]>;
100
+ };
101
+ declare function forUnit<TArgs extends Record<string, ArgumentValue>, TInputs extends Record<string, ComponentInputSpec>, TOutputs extends Record<string, ComponentInputSpec>, TSecrets extends Record<string, ArgumentValue>>(unit: Unit<TArgs, TInputs, TOutputs, TSecrets>): UnitContext<TArgs, InputSpecMapToValueMap<TInputs>, InputSpecMapToValueMap<TOutputs>, TSecrets>;
102
+ type EntityValue<T extends Entity> = Static<T["schema"]>;
103
+ type EntityInput<T extends Entity> = Output<EntityValue<T>>;
104
+
105
+ declare function getOrCreateSecret<TSecrets extends Record<string, unknown>, TResult extends TSecrets[keyof TSecrets]>(secrets: Output<TSecrets>, key: keyof TSecrets, create: () => Input<TResult>): Output<TResult>;
77
106
 
78
- export { type DeepInput, type EntityInput, type InputArray, type InputMap, type InputOrArray, type UnitContext, flattenInputs, forUnit, mapInputs, mapOptional, mergeInputs, mergeMapInputs, namedSingleton, singleton, toPromise };
107
+ export { type DeepInput, type EntityInput, type EntityValue, type ExtraOutputs, type InputArray, type InputMap, type InputOrArray, type Representation, type StatusField, type TerminalFactory, type UnitContext, flattenInputs, forUnit, getOrCreateSecret, mapInputs, mapOptional, mergeInputs, mergeMapInputs, namedSingleton, singleton, toPromise };
package/dist/index.mjs CHANGED
@@ -1,8 +1,199 @@
1
- import { all, output } from '@pulumi/pulumi';
1
+ import { secret, Config, output, getStack, Output, StackReference, all } from '@pulumi/pulumi';
2
2
  export * from '@pulumi/pulumi';
3
+ import { parseInstanceId } from '@highstate/contract';
4
+ import { Type } from '@sinclair/typebox';
5
+ import { Ajv } from 'ajv';
3
6
 
7
+ function u$1(t,n,a){let o=r=>t(r,...n);return a===undefined?o:Object.assign(o,{lazy:a,lazyArgs:n})}
8
+
9
+ function u(r,n,a){let o=r.length-n.length;if(o===0)return r(...n);if(o===1)return u$1(r,n,a);throw new Error("Wrong number of arguments")}
10
+
11
+ function i(...e){return u(o,e)}function o(e,r){let a={};for(let[n,u]of Object.entries(e)){let l=r(u,n,e);a[n]=l;}return a}
12
+
13
+ const createdSecrets = {};
14
+ function getOrCreateSecret(secrets, key, create) {
15
+ return secrets[key].apply((value) => {
16
+ if (value !== undefined) {
17
+ createdSecrets[key] = value;
18
+ return value;
19
+ }
20
+ const secretValue = createdSecrets[key] ?? secret(create());
21
+ createdSecrets[key] = secretValue;
22
+ return secretValue;
23
+ });
24
+ }
25
+
26
+ const ajv = new Ajv();
27
+ const stackRefMap = /* @__PURE__ */ new Map();
28
+ function getStackRef(input) {
29
+ const [instanceType, instanceName] = parseInstanceId(input.instanceId);
30
+ const key = `organization/${instanceType}/${instanceName}`;
31
+ if (!stackRefMap.has(key)) {
32
+ stackRefMap.set(key, new StackReference(key));
33
+ }
34
+ return stackRefMap.get(key);
35
+ }
36
+ function getOutput(unit, input, refOrRefs) {
37
+ const entity = unit.entities.get(input.type);
38
+ if (!entity) {
39
+ throw new Error(`Entity '${input.type}' not found in the unit '${unit.model.type}'.`);
40
+ }
41
+ const _getOutput = (ref) => {
42
+ const value = getStackRef(ref).requireOutput(ref.output);
43
+ return value.apply((value2) => {
44
+ let schema = entity.schema;
45
+ if (input.multiple) {
46
+ schema = Type.Union([schema, Type.Array(schema)]);
47
+ }
48
+ if (!ajv.validate(schema, value2)) {
49
+ throw new Error(`Invalid output for '${input.type}': ${ajv.errorsText()}`);
50
+ }
51
+ if (Array.isArray(value2)) {
52
+ return value2;
53
+ }
54
+ return input.multiple ? [value2] : value2;
55
+ });
56
+ };
57
+ if (Array.isArray(refOrRefs)) {
58
+ return output(refOrRefs.map((ref) => _getOutput(ref))).apply((values) => values.flat());
59
+ }
60
+ return _getOutput(refOrRefs);
61
+ }
62
+ function isAnyOfSchema(schema, itemType) {
63
+ if (schema.anyOf) {
64
+ return Object.values(schema.anyOf).every(
65
+ (schema2) => isAnyOfSchema(schema2, itemType)
66
+ );
67
+ }
68
+ return schema.type === itemType;
69
+ }
70
+ function isStringSchema(schema) {
71
+ if (schema.type === "string") {
72
+ return true;
73
+ }
74
+ if (isAnyOfSchema(schema, "string")) {
75
+ return true;
76
+ }
77
+ return false;
78
+ }
79
+ function isNumberSchema(schema) {
80
+ if (schema.type === "number") {
81
+ return true;
82
+ }
83
+ if (isAnyOfSchema(schema, "number")) {
84
+ return true;
85
+ }
86
+ return false;
87
+ }
88
+ function isBooleanSchema(schema) {
89
+ if (schema.type === "boolean") {
90
+ return true;
91
+ }
92
+ if (isAnyOfSchema(schema, "boolean")) {
93
+ return true;
94
+ }
95
+ return false;
96
+ }
4
97
  function forUnit(unit) {
5
- throw new Error("Not implemented");
98
+ const config = new Config();
99
+ const args = i(unit.model.args, (arg, argName) => {
100
+ switch (true) {
101
+ case isStringSchema(arg.schema): {
102
+ return arg.required ? config.require(argName) : config.get(argName);
103
+ }
104
+ case isNumberSchema(arg.schema): {
105
+ return arg.required ? config.requireNumber(argName) : config.getNumber(argName);
106
+ }
107
+ case isBooleanSchema(arg.schema): {
108
+ return arg.required ? config.requireBoolean(argName) : config.getBoolean(argName);
109
+ }
110
+ default: {
111
+ const value = arg.required ? config.requireObject(argName) : config.getObject(argName);
112
+ if (value === undefined) return undefined;
113
+ if (!ajv.validate(arg.schema, value)) {
114
+ throw new Error(`Invalid config for '${argName}': ${ajv.errorsText()}`);
115
+ }
116
+ return value;
117
+ }
118
+ }
119
+ });
120
+ const secrets = output(
121
+ i(unit.model.secrets, (secret, secretName) => {
122
+ switch (true) {
123
+ case isStringSchema(secret.schema): {
124
+ return secret.required ? config.requireSecret(secretName) : config.getSecret(secretName);
125
+ }
126
+ case isNumberSchema(secret.schema): {
127
+ return secret.required ? config.requireSecretNumber(secretName) : config.getSecretNumber(secretName);
128
+ }
129
+ case isBooleanSchema(secret.schema): {
130
+ return secret.required ? config.requireSecretBoolean(secretName) : config.getSecretBoolean(secretName);
131
+ }
132
+ default: {
133
+ const value = secret.required ? config.requireSecretObject(secretName) : config.getSecretObject(secretName);
134
+ if (!ajv.validate(secret.schema, value)) {
135
+ throw new Error(`Invalid secret for '${secretName}': ${ajv.errorsText()}`);
136
+ }
137
+ return value;
138
+ }
139
+ }
140
+ })
141
+ );
142
+ const inputs = output(
143
+ i(unit.model.inputs, (input, inputName) => {
144
+ const value = input.required ? config.requireObject(`input.${inputName}`) : config.getObject(`input.${inputName}`);
145
+ if (!value) {
146
+ if (input.multiple) {
147
+ return output([]);
148
+ }
149
+ return output(undefined);
150
+ }
151
+ return getOutput(unit, input, value);
152
+ })
153
+ );
154
+ return {
155
+ args,
156
+ name: getStack(),
157
+ secrets,
158
+ inputs,
159
+ outputs: async (outputs) => {
160
+ const result = i(outputs, (outputValue, outputName) => {
161
+ if (outputName.startsWith("$")) {
162
+ if (Output.isInstance(outputValue)) {
163
+ return output(outputValue);
164
+ }
165
+ for (const key of Object.keys(outputValue)) {
166
+ outputValue[key] = output(outputValue[key]);
167
+ }
168
+ return outputValue;
169
+ }
170
+ const outputModel = unit.model.outputs[outputName];
171
+ if (!outputModel) {
172
+ throw new Error(`Output '${outputName}' not found in the unit '${unit.model.type}'.`);
173
+ }
174
+ const entity = unit.entities.get(outputModel.type);
175
+ if (!entity) {
176
+ throw new Error(
177
+ `Entity '${outputModel.type}' not found in the unit '${unit.model.type}'.`
178
+ );
179
+ }
180
+ return output(outputValue).apply((value) => {
181
+ if (!ajv.validate(entity.schema, value)) {
182
+ throw new Error(`Invalid output for '${outputModel.type}': ${ajv.errorsText()}`);
183
+ }
184
+ return value;
185
+ });
186
+ });
187
+ await Promise.all(Object.values(result).map((o) => outputToPromise(o)));
188
+ if (Object.keys(createdSecrets).length > 0) {
189
+ result.$secrets = createdSecrets;
190
+ }
191
+ return result;
192
+ }
193
+ };
194
+ }
195
+ function outputToPromise(o) {
196
+ return new Promise((resolve) => output(o).apply(resolve));
6
197
  }
7
198
 
8
199
  function mergeInputs(...values) {
@@ -32,8 +223,8 @@ function mergeMapInputs(...args) {
32
223
  return mapInputs(mergeInputs(...values), fn);
33
224
  }
34
225
  function mapOptional(input, func) {
35
- if (input === void 0) {
36
- return void 0;
226
+ if (input === undefined) {
227
+ return undefined;
37
228
  }
38
229
  return func(input);
39
230
  }
@@ -43,7 +234,7 @@ function toPromise(output2) {
43
234
  function singleton(factory) {
44
235
  let instance;
45
236
  return () => {
46
- if (instance === void 0) {
237
+ if (instance === undefined) {
47
238
  instance = factory();
48
239
  }
49
240
  return instance;
@@ -59,4 +250,4 @@ function namedSingleton(factory) {
59
250
  };
60
251
  }
61
252
 
62
- export { flattenInputs, forUnit, mapInputs, mapOptional, mergeInputs, mergeMapInputs, namedSingleton, singleton, toPromise };
253
+ export { flattenInputs, forUnit, getOrCreateSecret, mapInputs, mapOptional, mergeInputs, mergeMapInputs, namedSingleton, singleton, toPromise };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@highstate/pulumi",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "type": "module",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -17,15 +17,16 @@
17
17
  "access": "public"
18
18
  },
19
19
  "scripts": {
20
- "build": "pkgroll --clean-dist"
20
+ "build": "pkgroll --tsconfig=tsconfig.build.json"
21
21
  },
22
22
  "dependencies": {
23
- "@highstate/contract": "^0.4.1",
23
+ "@highstate/contract": "^0.4.2",
24
24
  "@pulumi/pulumi": "^3.142.0",
25
- "@sinclair/typebox": "^0.34.11"
25
+ "@sinclair/typebox": "^0.34.11",
26
+ "ajv": "^8.17.1"
26
27
  },
27
28
  "devDependencies": {
28
29
  "pkgroll": "^2.5.1"
29
30
  },
30
- "gitHead": "0ebd5c9d6f0176a38e8786d239a0b0828fa635f0"
31
+ "gitHead": "e88c7c588267cf028c054f694d402902dc057919"
31
32
  }