@highstate/pulumi 0.9.15 → 0.9.18
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/highstate.manifest.json +1 -1
- package/dist/index.js +211 -122
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/index.ts +1 -1
- package/src/secret.ts +54 -23
- package/src/unit.ts +301 -123
package/dist/index.js
CHANGED
@@ -1,38 +1,31 @@
|
|
1
|
-
|
2
|
-
export * from
|
3
|
-
|
4
|
-
|
5
|
-
import {
|
6
|
-
parseInstanceId,
|
7
|
-
getInstanceId
|
8
|
-
} from "@highstate/contract";
|
9
|
-
import { Type } from "@sinclair/typebox";
|
10
|
-
import { mapValues, pickBy, pipe } from "remeda";
|
11
|
-
import {
|
12
|
-
Config,
|
13
|
-
getStack,
|
14
|
-
output,
|
15
|
-
secret as secret2,
|
16
|
-
StackReference
|
17
|
-
} from "@pulumi/pulumi";
|
18
|
-
import { Ajv } from "ajv";
|
1
|
+
import { getStack, secret, output, Config, all, StackReference } from '@pulumi/pulumi';
|
2
|
+
export * from '@pulumi/pulumi';
|
3
|
+
import { HighstateSignature, getInstanceId, camelCaseToHumanReadable, unitArtifactSchema, unitSecretSchema, parseInstanceId } from '@highstate/contract';
|
4
|
+
import { mapValues, pipe, pickBy } from 'remeda';
|
5
|
+
import { Ajv } from 'ajv';
|
19
6
|
|
20
|
-
// src/
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
7
|
+
// src/index.ts
|
8
|
+
var updatedSecretValues = {};
|
9
|
+
function ensureSecretValue(secret2, create) {
|
10
|
+
return {
|
11
|
+
[HighstateSignature.Secret]: true,
|
12
|
+
id: secret2.id,
|
13
|
+
value: secret2.value.apply((value) => {
|
14
|
+
if (value !== void 0) {
|
15
|
+
return value;
|
16
|
+
}
|
17
|
+
updatedSecretValues[secret2.id] = secret(create());
|
18
|
+
return updatedSecretValues[secret2.id];
|
19
|
+
})
|
20
|
+
};
|
33
21
|
}
|
34
|
-
function
|
35
|
-
|
22
|
+
function updateSecretValue(secret2, value) {
|
23
|
+
updatedSecretValues[secret2.id] = secret(value);
|
24
|
+
return {
|
25
|
+
[HighstateSignature.Secret]: true,
|
26
|
+
id: secret2.id,
|
27
|
+
value: output(updatedSecretValues[secret2.id])
|
28
|
+
};
|
36
29
|
}
|
37
30
|
|
38
31
|
// src/unit.ts
|
@@ -68,12 +61,16 @@ function getOutput(unit, input, refs) {
|
|
68
61
|
const _getOutput = (ref) => {
|
69
62
|
const value = getStackRef(ref).requireOutput(ref.output);
|
70
63
|
return value.apply((value2) => {
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
64
|
+
if (Array.isArray(value2)) {
|
65
|
+
for (const [index, item] of value2.entries()) {
|
66
|
+
if (!ajv.validate(entity.schema, item)) {
|
67
|
+
throw new Error(`Invalid output for '${input.type}[${index}]': ${ajv.errorsText()}`);
|
68
|
+
}
|
69
|
+
}
|
70
|
+
} else {
|
71
|
+
if (!ajv.validate(entity.schema, value2)) {
|
72
|
+
throw new Error(`Invalid output for '${input.type}': ${ajv.errorsText()}`);
|
73
|
+
}
|
77
74
|
}
|
78
75
|
if (Array.isArray(value2)) {
|
79
76
|
return value2;
|
@@ -89,9 +86,7 @@ function getOutput(unit, input, refs) {
|
|
89
86
|
}
|
90
87
|
function isAnyOfSchema(schema, itemType) {
|
91
88
|
if (schema.anyOf) {
|
92
|
-
return Object.values(schema.anyOf).every(
|
93
|
-
(schema2) => isAnyOfSchema(schema2, itemType)
|
94
|
-
);
|
89
|
+
return Object.values(schema.anyOf).every((schema2) => isAnyOfSchema(schema2, itemType));
|
95
90
|
}
|
96
91
|
return schema.type === itemType;
|
97
92
|
}
|
@@ -127,15 +122,38 @@ function forUnit(unit) {
|
|
127
122
|
const args = mapValues(unit.model.args, (arg, argName) => {
|
128
123
|
switch (true) {
|
129
124
|
case isStringSchema(arg.schema): {
|
130
|
-
|
125
|
+
if (arg.required) {
|
126
|
+
return config.require(argName);
|
127
|
+
}
|
128
|
+
return config.get(argName) || arg.schema.default;
|
131
129
|
}
|
132
130
|
case isNumberSchema(arg.schema): {
|
133
|
-
|
131
|
+
if (arg.required) {
|
132
|
+
return config.requireNumber(argName);
|
133
|
+
}
|
134
|
+
const value = config.get(argName);
|
135
|
+
if (!value) {
|
136
|
+
return arg.schema.default;
|
137
|
+
}
|
138
|
+
return config.getNumber(argName) ?? arg.schema.default;
|
134
139
|
}
|
135
140
|
case isBooleanSchema(arg.schema): {
|
136
|
-
|
141
|
+
if (arg.required) {
|
142
|
+
return config.requireBoolean(argName);
|
143
|
+
}
|
144
|
+
const value = config.get(argName);
|
145
|
+
if (!value) {
|
146
|
+
return arg.schema.default;
|
147
|
+
}
|
148
|
+
return config.getBoolean(argName) ?? arg.schema.default;
|
137
149
|
}
|
138
150
|
default: {
|
151
|
+
if (!arg.required) {
|
152
|
+
const value2 = config.get(argName);
|
153
|
+
if (!value2) {
|
154
|
+
return arg.schema.default;
|
155
|
+
}
|
156
|
+
}
|
139
157
|
const value = arg.required ? config.requireObject(argName) : config.getObject(argName);
|
140
158
|
if (value === void 0) return arg.schema.default;
|
141
159
|
if (!ajv.validate(arg.schema, value)) {
|
@@ -145,28 +163,38 @@ function forUnit(unit) {
|
|
145
163
|
}
|
146
164
|
}
|
147
165
|
});
|
148
|
-
const
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
}
|
165
|
-
return value;
|
166
|
+
const secretIds = config.requireObject("$secretIds");
|
167
|
+
const getSecretValue = (secretName, secret2) => {
|
168
|
+
switch (true) {
|
169
|
+
case isStringSchema(secret2.schema): {
|
170
|
+
return secret2.required ? config.requireSecret(secretName) : config.getSecret(secretName);
|
171
|
+
}
|
172
|
+
case isNumberSchema(secret2.schema): {
|
173
|
+
return secret2.required ? config.requireSecretNumber(secretName) : config.getSecretNumber(secretName);
|
174
|
+
}
|
175
|
+
case isBooleanSchema(secret2.schema): {
|
176
|
+
return secret2.required ? config.requireSecretBoolean(secretName) : config.getSecretBoolean(secretName);
|
177
|
+
}
|
178
|
+
default: {
|
179
|
+
const value = secret2.required ? config.requireSecretObject(secretName) : config.getSecretObject(secretName);
|
180
|
+
if (!ajv.validate(secret2.schema, value)) {
|
181
|
+
throw new Error(`Invalid secret for '${secretName}': ${ajv.errorsText()}`);
|
166
182
|
}
|
183
|
+
return value;
|
167
184
|
}
|
168
|
-
}
|
169
|
-
|
185
|
+
}
|
186
|
+
};
|
187
|
+
const secrets = mapValues(unit.model.secrets, (secret2, secretName) => {
|
188
|
+
const secretId = secretIds[secretName];
|
189
|
+
if (!secretId) {
|
190
|
+
throw new Error(`Secret '${secretName}' not found in the config.`);
|
191
|
+
}
|
192
|
+
return {
|
193
|
+
[HighstateSignature.Secret]: true,
|
194
|
+
id: secretId,
|
195
|
+
value: secret2.required ? config.requireSecret(secretName) : output(getSecretValue(secretName, secret2))
|
196
|
+
};
|
197
|
+
});
|
170
198
|
const inputs = mapValues(unit.model.inputs, (input, inputName) => {
|
171
199
|
const value = input.required ? config.requireObject(`input.${inputName}`) : config.getObject(`input.${inputName}`);
|
172
200
|
if (!value) {
|
@@ -189,15 +217,12 @@ function forUnit(unit) {
|
|
189
217
|
invokedTriggers: config.getObject("$invokedTriggers") ?? [],
|
190
218
|
outputs: async (outputs = {}) => {
|
191
219
|
const result = mapValues(outputs, (outputValue, outputName) => {
|
192
|
-
if (outputName === "$
|
193
|
-
return output(outputValue).apply(
|
220
|
+
if (outputName === "$statusFields") {
|
221
|
+
return output(outputValue).apply(mapStatusFields);
|
194
222
|
}
|
195
223
|
if (outputName === "$pages") {
|
196
224
|
return output(outputValue).apply(mapPages);
|
197
225
|
}
|
198
|
-
if (outputName === "$files") {
|
199
|
-
return output(outputValue).apply(mapFiles);
|
200
|
-
}
|
201
226
|
if (outputName === "$terminals") {
|
202
227
|
return output(outputValue).apply(mapTerminals);
|
203
228
|
}
|
@@ -224,7 +249,7 @@ function forUnit(unit) {
|
|
224
249
|
}
|
225
250
|
return void 0;
|
226
251
|
}
|
227
|
-
const schema = outputModel.multiple ?
|
252
|
+
const schema = outputModel.multiple ? entity.schema.array() : entity.schema;
|
228
253
|
if (!ajv.validate(schema, value)) {
|
229
254
|
throw new Error(`Invalid output for '${outputName}': ${ajv.errorsText()}`);
|
230
255
|
}
|
@@ -232,8 +257,32 @@ function forUnit(unit) {
|
|
232
257
|
});
|
233
258
|
});
|
234
259
|
await Promise.all(Object.values(result).map((o) => outputToPromise(o)));
|
235
|
-
|
236
|
-
|
260
|
+
result.$secrets = updatedSecretValues;
|
261
|
+
const secretsMap = {};
|
262
|
+
for (const [outputName, outputValue] of Object.entries(outputs)) {
|
263
|
+
if (!outputName.startsWith("$")) {
|
264
|
+
const resolvedValue = await outputToPromise(outputValue);
|
265
|
+
const secrets2 = extractObjectsFromValue(unitSecretSchema, resolvedValue);
|
266
|
+
if (secrets2.length > 0) {
|
267
|
+
secretsMap[outputName] = secrets2;
|
268
|
+
}
|
269
|
+
}
|
270
|
+
}
|
271
|
+
const artifactsMap = {};
|
272
|
+
for (const [outputName, outputValue] of Object.entries(outputs)) {
|
273
|
+
if (!outputName.startsWith("$")) {
|
274
|
+
const resolvedValue = await outputToPromise(outputValue);
|
275
|
+
const artifacts = extractObjectsFromValue(unitArtifactSchema, resolvedValue);
|
276
|
+
if (artifacts.length > 0) {
|
277
|
+
artifactsMap[outputName] = artifacts;
|
278
|
+
}
|
279
|
+
}
|
280
|
+
}
|
281
|
+
if (Object.keys(artifactsMap).length > 0) {
|
282
|
+
result.$exportedArtifacts = artifactsMap;
|
283
|
+
}
|
284
|
+
if (Object.keys(secretsMap).length > 0) {
|
285
|
+
result.$exportedSecretIds = mapValues(secretsMap, (v) => v.map((secret2) => secret2.id));
|
237
286
|
}
|
238
287
|
return result;
|
239
288
|
}
|
@@ -242,21 +291,42 @@ function forUnit(unit) {
|
|
242
291
|
function outputToPromise(o) {
|
243
292
|
return new Promise((resolve) => output(o).apply(resolve));
|
244
293
|
}
|
245
|
-
function
|
294
|
+
function mapStatusFields(status) {
|
246
295
|
if (!status) {
|
247
296
|
return [];
|
248
297
|
}
|
249
298
|
if (Array.isArray(status)) {
|
250
|
-
return status.filter((field) => !!field?.value)
|
299
|
+
return status.filter((field) => !!field?.value).map((field) => {
|
300
|
+
return {
|
301
|
+
name: field.name,
|
302
|
+
meta: {
|
303
|
+
title: field.meta?.title ?? camelCaseToHumanReadable(field.name)
|
304
|
+
},
|
305
|
+
value: field.value
|
306
|
+
};
|
307
|
+
});
|
251
308
|
}
|
252
309
|
return Object.entries(status).map(([name, field]) => {
|
253
310
|
if (!field) {
|
254
311
|
return void 0;
|
255
312
|
}
|
256
313
|
if (typeof field === "string" || typeof field === "number" || typeof field === "boolean" || Array.isArray(field)) {
|
257
|
-
return {
|
314
|
+
return {
|
315
|
+
name,
|
316
|
+
meta: {
|
317
|
+
title: camelCaseToHumanReadable(name)
|
318
|
+
},
|
319
|
+
value: field
|
320
|
+
};
|
258
321
|
}
|
259
|
-
return {
|
322
|
+
return {
|
323
|
+
...field,
|
324
|
+
meta: {
|
325
|
+
...field.meta,
|
326
|
+
title: field.meta?.title ?? camelCaseToHumanReadable(name)
|
327
|
+
},
|
328
|
+
name
|
329
|
+
};
|
260
330
|
}).filter((field) => !!field?.value);
|
261
331
|
}
|
262
332
|
function mapPages(pages) {
|
@@ -275,7 +345,10 @@ function fileFromString(name, content, contentType = "text/plain", isSecret = fa
|
|
275
345
|
contentType,
|
276
346
|
size: Buffer.byteLength(content, "utf8")
|
277
347
|
},
|
278
|
-
content:
|
348
|
+
content: {
|
349
|
+
type: "embedded",
|
350
|
+
value: isSecret ? secret(content) : content
|
351
|
+
}
|
279
352
|
};
|
280
353
|
}
|
281
354
|
function fileFromBuffer(name, content, contentType = "application/octet-stream", isSecret = false) {
|
@@ -286,12 +359,12 @@ function fileFromBuffer(name, content, contentType = "application/octet-stream",
|
|
286
359
|
size: content.byteLength,
|
287
360
|
isBinary: true
|
288
361
|
},
|
289
|
-
content:
|
362
|
+
content: {
|
363
|
+
type: "embedded",
|
364
|
+
value: isSecret ? secret(content.toString("base64")) : content.toString("base64")
|
365
|
+
}
|
290
366
|
};
|
291
367
|
}
|
292
|
-
function mapFiles(files) {
|
293
|
-
return files?.filter((file) => !!file) ?? [];
|
294
|
-
}
|
295
368
|
function mapTerminals(terminals) {
|
296
369
|
if (!terminals) {
|
297
370
|
return [];
|
@@ -305,21 +378,34 @@ function mapTerminals(terminals) {
|
|
305
378
|
});
|
306
379
|
}
|
307
380
|
return terminals.filter((terminal) => !!terminal).map((terminal) => {
|
308
|
-
if (!terminal.files) {
|
381
|
+
if (!terminal.spec.files) {
|
309
382
|
return terminal;
|
310
383
|
}
|
311
384
|
return {
|
312
385
|
...terminal,
|
313
|
-
|
314
|
-
terminal.
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
386
|
+
spec: {
|
387
|
+
...terminal.spec,
|
388
|
+
files: pipe(
|
389
|
+
terminal.spec.files,
|
390
|
+
mapValues((file) => {
|
391
|
+
if (typeof file === "string") {
|
392
|
+
return {
|
393
|
+
meta: {
|
394
|
+
name: "content",
|
395
|
+
contentType: "text/plain",
|
396
|
+
size: Buffer.byteLength(file, "utf8")
|
397
|
+
},
|
398
|
+
content: {
|
399
|
+
type: "embedded",
|
400
|
+
value: file
|
401
|
+
}
|
402
|
+
};
|
403
|
+
}
|
404
|
+
return file;
|
405
|
+
}),
|
406
|
+
pickBy((value) => !!value)
|
407
|
+
)
|
408
|
+
}
|
323
409
|
};
|
324
410
|
});
|
325
411
|
}
|
@@ -332,9 +418,30 @@ function mapTriggers(triggers) {
|
|
332
418
|
}
|
333
419
|
return Object.entries(triggers).filter(([, trigger]) => !!trigger).map(([name, trigger]) => ({ ...trigger, name }));
|
334
420
|
}
|
335
|
-
|
336
|
-
|
337
|
-
|
421
|
+
function extractObjectsFromValue(schema, data) {
|
422
|
+
const result = [];
|
423
|
+
function traverse(obj) {
|
424
|
+
if (obj === null || obj === void 0 || typeof obj !== "object") {
|
425
|
+
return;
|
426
|
+
}
|
427
|
+
if (Array.isArray(obj)) {
|
428
|
+
for (const item of obj) {
|
429
|
+
traverse(item);
|
430
|
+
}
|
431
|
+
return;
|
432
|
+
}
|
433
|
+
const parseResult = schema.safeParse(obj);
|
434
|
+
if (parseResult.success) {
|
435
|
+
result.push(parseResult.data);
|
436
|
+
return;
|
437
|
+
}
|
438
|
+
for (const value of Object.values(obj)) {
|
439
|
+
traverse(value);
|
440
|
+
}
|
441
|
+
}
|
442
|
+
traverse(data);
|
443
|
+
return result;
|
444
|
+
}
|
338
445
|
function flattenInputs(...values) {
|
339
446
|
return all(values).apply((allValues) => {
|
340
447
|
const result = [];
|
@@ -349,7 +456,7 @@ function flattenInputs(...values) {
|
|
349
456
|
});
|
350
457
|
}
|
351
458
|
function mapInputs(array, fn) {
|
352
|
-
return
|
459
|
+
return output(array).apply((array2) => {
|
353
460
|
return array2?.map((v, index) => fn(v, index, array2)) ?? [];
|
354
461
|
});
|
355
462
|
}
|
@@ -365,7 +472,7 @@ function mapOptional(input, func) {
|
|
365
472
|
return func(input);
|
366
473
|
}
|
367
474
|
function toPromise(input) {
|
368
|
-
return new Promise((resolve) =>
|
475
|
+
return new Promise((resolve) => output(input).apply(resolve));
|
369
476
|
}
|
370
477
|
function singleton(factory) {
|
371
478
|
let instance;
|
@@ -386,7 +493,7 @@ function providerFactory(factory) {
|
|
386
493
|
};
|
387
494
|
}
|
388
495
|
function mergeInputObjects(...objects) {
|
389
|
-
return
|
496
|
+
return output(objects).apply((array) => {
|
390
497
|
return Object.assign({}, ...array);
|
391
498
|
});
|
392
499
|
}
|
@@ -400,30 +507,12 @@ function normalize(item, collection) {
|
|
400
507
|
return collection ?? [];
|
401
508
|
}
|
402
509
|
function apply(fn) {
|
403
|
-
return (input) =>
|
510
|
+
return (input) => output(input).apply(fn);
|
404
511
|
}
|
405
512
|
function applyMap(fn) {
|
406
|
-
return (input) =>
|
513
|
+
return (input) => output(input).apply((array) => array.map(fn));
|
407
514
|
}
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
fileFromBuffer,
|
412
|
-
fileFromString,
|
413
|
-
flatMapInput,
|
414
|
-
flattenInputs,
|
415
|
-
forUnit,
|
416
|
-
getOrCreateSecret,
|
417
|
-
getResourceComment,
|
418
|
-
getUnitInstanceId,
|
419
|
-
getUnitInstanceName,
|
420
|
-
mapInputs,
|
421
|
-
mapOptional,
|
422
|
-
mergeInputObjects,
|
423
|
-
normalize,
|
424
|
-
providerFactory,
|
425
|
-
singleton,
|
426
|
-
storeSecret,
|
427
|
-
toPromise
|
428
|
-
};
|
515
|
+
|
516
|
+
export { apply, applyMap, ensureSecretValue, fileFromBuffer, fileFromString, flatMapInput, flattenInputs, forUnit, getResourceComment, getUnitInstanceId, getUnitInstanceName, mapInputs, mapOptional, mergeInputObjects, normalize, providerFactory, singleton, toPromise, updateSecretValue };
|
517
|
+
//# sourceMappingURL=index.js.map
|
429
518
|
//# sourceMappingURL=index.js.map
|