@highstate/pulumi 0.7.2 → 0.7.4

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.
@@ -0,0 +1,5 @@
1
+ {
2
+ "sourceHashes": {
3
+ "./dist/index.js": "69a7792af11718e459a63de92865bd5008c3174002b47a8c31ba3b2bd65ccd8e"
4
+ }
5
+ }
@@ -1,11 +1,25 @@
1
- import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { secret, getStack, Config, output, StackReference, all } from '@pulumi/pulumi';
2
- export * from '@pulumi/pulumi';
3
- import { getInstanceId, parseInstanceId } from '@highstate/contract';
4
- import { Type } from '@sinclair/typebox';
5
- import { mapValues, pipe, pickBy } from 'remeda';
6
- import { Ajv } from 'ajv';
1
+ // src/index.ts
2
+ export * from "@pulumi/pulumi";
7
3
 
8
- const createdSecrets = {};
4
+ // src/unit.ts
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";
19
+
20
+ // src/secret.ts
21
+ import { secret } from "@pulumi/pulumi";
22
+ var createdSecrets = {};
9
23
  function getOrCreateSecret(secrets, key, create) {
10
24
  return secrets[key].apply((value) => {
11
25
  if (value !== void 0) {
@@ -18,9 +32,20 @@ function getOrCreateSecret(secrets, key, create) {
18
32
  });
19
33
  }
20
34
 
21
- const ajv = new Ajv();
22
- const stackRefMap = /* @__PURE__ */ new Map();
23
- const [projectId, instanceName] = getStack().split("_");
35
+ // src/unit.ts
36
+ var ajv = new Ajv();
37
+ var stackRefMap = /* @__PURE__ */ new Map();
38
+ var [projectId, instanceName] = getStack().split("_");
39
+ var instanceId;
40
+ function getUnitInstanceId() {
41
+ if (!instanceId) {
42
+ throw new Error("Instance id is not set. Did you call 'forUnit' function?");
43
+ }
44
+ return instanceId;
45
+ }
46
+ function getUnitInstanceName() {
47
+ return instanceName;
48
+ }
24
49
  function getStackRef(input) {
25
50
  const [instanceType, instanceName2] = parseInstanceId(input.instanceId);
26
51
  const key = `organization/${instanceType}/${projectId}_${instanceName2}`;
@@ -115,20 +140,20 @@ function forUnit(unit) {
115
140
  }
116
141
  });
117
142
  const secrets = output(
118
- mapValues(unit.model.secrets, (secret, secretName) => {
143
+ mapValues(unit.model.secrets, (secret3, secretName) => {
119
144
  switch (true) {
120
- case isStringSchema(secret.schema): {
121
- return secret.required ? config.requireSecret(secretName) : config.getSecret(secretName);
145
+ case isStringSchema(secret3.schema): {
146
+ return secret3.required ? config.requireSecret(secretName) : config.getSecret(secretName);
122
147
  }
123
- case isNumberSchema(secret.schema): {
124
- return secret.required ? config.requireSecretNumber(secretName) : config.getSecretNumber(secretName);
148
+ case isNumberSchema(secret3.schema): {
149
+ return secret3.required ? config.requireSecretNumber(secretName) : config.getSecretNumber(secretName);
125
150
  }
126
- case isBooleanSchema(secret.schema): {
127
- return secret.required ? config.requireSecretBoolean(secretName) : config.getSecretBoolean(secretName);
151
+ case isBooleanSchema(secret3.schema): {
152
+ return secret3.required ? config.requireSecretBoolean(secretName) : config.getSecretBoolean(secretName);
128
153
  }
129
154
  default: {
130
- const value = secret.required ? config.requireSecretObject(secretName) : config.getSecretObject(secretName);
131
- if (!ajv.validate(secret.schema, value)) {
155
+ const value = secret3.required ? config.requireSecretObject(secretName) : config.getSecretObject(secretName);
156
+ if (!ajv.validate(secret3.schema, value)) {
132
157
  throw new Error(`Invalid secret for '${secretName}': ${ajv.errorsText()}`);
133
158
  }
134
159
  return value;
@@ -147,9 +172,10 @@ function forUnit(unit) {
147
172
  return getOutput(unit, input, value);
148
173
  });
149
174
  const type = unit.model.type;
175
+ instanceId = getInstanceId(type, instanceName);
150
176
  return {
151
177
  args,
152
- instanceId: getInstanceId(type, instanceName),
178
+ instanceId,
153
179
  type,
154
180
  name: instanceName,
155
181
  secrets,
@@ -235,14 +261,29 @@ function mapPages(pages) {
235
261
  }
236
262
  return Object.entries(pages).filter(([, page]) => !!page).map(([name, page]) => ({ ...page, name }));
237
263
  }
264
+ function fileFromString(name, content, contentType = "text/plain", isSecret = false) {
265
+ return {
266
+ meta: {
267
+ name,
268
+ contentType,
269
+ size: Buffer.byteLength(content, "utf8")
270
+ },
271
+ content: isSecret ? secret2(content) : content
272
+ };
273
+ }
274
+ function fileFromBuffer(name, content, contentType = "application/octet-stream", isSecret = false) {
275
+ return {
276
+ meta: {
277
+ name,
278
+ contentType,
279
+ size: content.byteLength,
280
+ isBinary: true
281
+ },
282
+ content: isSecret ? secret2(content.toString("base64")) : content.toString("base64")
283
+ };
284
+ }
238
285
  function mapFiles(files) {
239
- if (!files) {
240
- return [];
241
- }
242
- if (Array.isArray(files)) {
243
- return files.filter((file) => !!file);
244
- }
245
- return Object.entries(files).filter(([, file]) => !!file).map(([name, file]) => ({ ...file, name }));
286
+ return files?.filter((file) => !!file) ?? [];
246
287
  }
247
288
  function mapTerminals(terminals) {
248
289
  if (!terminals) {
@@ -285,6 +326,8 @@ function mapTriggers(triggers) {
285
326
  return Object.entries(triggers).filter(([, trigger]) => !!trigger).map(([name, trigger]) => ({ ...trigger, name }));
286
327
  }
287
328
 
329
+ // src/utils.ts
330
+ import { output as output2, all } from "@pulumi/pulumi";
288
331
  function flattenInputs(...values) {
289
332
  return all(values).apply((allValues) => {
290
333
  const result = [];
@@ -299,7 +342,7 @@ function flattenInputs(...values) {
299
342
  });
300
343
  }
301
344
  function mapInputs(array, fn) {
302
- return output(array).apply((array2) => {
345
+ return output2(array).apply((array2) => {
303
346
  return array2?.map((v, index) => fn(v, index, array2)) ?? [];
304
347
  });
305
348
  }
@@ -315,7 +358,7 @@ function mapOptional(input, func) {
315
358
  return func(input);
316
359
  }
317
360
  function toPromise(input) {
318
- return new Promise((resolve) => output(input).apply(resolve));
361
+ return new Promise((resolve) => output2(input).apply(resolve));
319
362
  }
320
363
  function singleton(factory) {
321
364
  let instance;
@@ -336,7 +379,7 @@ function providerFactory(factory) {
336
379
  };
337
380
  }
338
381
  function mergeInputObjects(...objects) {
339
- return output(objects).apply((array) => {
382
+ return output2(objects).apply((array) => {
340
383
  return Object.assign({}, ...array);
341
384
  });
342
385
  }
@@ -350,7 +393,24 @@ function normalize(item, collection) {
350
393
  return collection ?? [];
351
394
  }
352
395
  function apply(fn) {
353
- return (input) => output(input).apply(fn);
396
+ return (input) => output2(input).apply(fn);
354
397
  }
355
-
356
- export { apply, flatMapInput, flattenInputs, forUnit, getOrCreateSecret, mapInputs, mapOptional, mergeInputObjects, normalize, providerFactory, singleton, toPromise };
398
+ export {
399
+ apply,
400
+ fileFromBuffer,
401
+ fileFromString,
402
+ flatMapInput,
403
+ flattenInputs,
404
+ forUnit,
405
+ getOrCreateSecret,
406
+ getUnitInstanceId,
407
+ getUnitInstanceName,
408
+ mapInputs,
409
+ mapOptional,
410
+ mergeInputObjects,
411
+ normalize,
412
+ providerFactory,
413
+ singleton,
414
+ toPromise
415
+ };
416
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/unit.ts","../src/secret.ts","../src/utils.ts"],"sourcesContent":["export * from \"@pulumi/pulumi\"\nexport * from \"./unit\"\nexport * from \"./utils\"\nexport { getOrCreateSecret } from \"./secret\"\n","/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { DeepInput, InputArray, InputMap } from \"./utils\"\nimport {\n type ArgumentValue,\n type ComponentInputSpec,\n type Entity,\n type Unit,\n type ComponentInput,\n type InstanceInput,\n parseInstanceId,\n type ArgumentValueSchema,\n getInstanceId,\n} from \"@highstate/contract\"\nimport { Type, type Static } from \"@sinclair/typebox\"\nimport { mapValues, pickBy, pipe } from \"remeda\"\nimport {\n Config,\n getStack,\n Output,\n output,\n secret,\n StackReference,\n type Input,\n type Unwrap,\n} from \"@pulumi/pulumi\"\nimport { Ajv } from \"ajv\"\nimport { createdSecrets } from \"./secret\"\n\nconst ajv = new Ajv()\n\nexport type InstanceTerminalFile = {\n content: Input<string | undefined>\n mode?: Input<number | undefined>\n isBinary?: Input<boolean>\n}\n\nexport type InstanceTerminal = {\n name: Input<string>\n title: Input<string>\n description?: Input<string>\n image: Input<string>\n command: InputArray<string>\n cwd?: Input<string | undefined>\n env?: InputMap<string | undefined>\n files?: InputMap<InstanceTerminalFile | string | undefined>\n}\n\nexport type StatusField<TArgName extends string = string> = {\n name: Input<string>\n value?: Input<string | undefined>\n displayName?: Input<string | undefined>\n sensitive?: Input<boolean | undefined>\n url?: Input<string | undefined>\n complementaryTo?: Input<TArgName | undefined>\n}\n\nexport type InstanceFileMeta = {\n name: Input<string>\n contentType: Input<string>\n isBinary?: Input<boolean>\n size: Input<number>\n}\n\nexport type InstanceFile = {\n meta: Input<InstanceFileMeta>\n content: Input<string>\n}\n\nexport type InstancePageBlock =\n | { type: \"markdown\"; content: Input<string> }\n | { type: \"qr\"; content: Input<string>; showContent?: boolean; language?: string }\n | { type: \"file\"; fileMeta: Input<InstanceFileMeta> }\n\nexport type InstancePage = {\n name: Input<string>\n title: Input<string>\n content: InputArray<InstancePageBlock>\n}\n\nexport type InstanceTriggerSpec =\n | {\n type: \"before-destroy\"\n }\n | {\n type: \"schedule\"\n schedule: string\n }\n\nexport type InstanceTrigger = {\n name: Input<string>\n title: Input<string>\n description?: Input<string>\n spec: Input<InstanceTriggerSpec>\n}\n\nexport type ExtraOutputs<TArgName extends string = string> = {\n $status?:\n | InputMap<Omit<StatusField<TArgName>, \"name\"> | string | undefined>\n | InputArray<StatusField<TArgName> | undefined>\n\n $terminals?:\n | InputMap<Omit<InstanceTerminal, \"name\"> | undefined>\n | InputArray<InstanceTerminal | undefined>\n\n $pages?: InputMap<Omit<InstancePage, \"name\"> | undefined> | InputArray<InstancePage | undefined>\n $files?: InputArray<InstanceFile | undefined>\n\n $triggers?:\n | InputMap<Omit<InstanceTrigger, \"name\"> | undefined>\n | InputArray<InstanceTrigger | undefined>\n}\n\nexport type InstanceTriggerInvocation = {\n name: string\n}\n\ntype OutputMapToDeepInputMap<T extends Record<string, unknown>, TArgName extends string> =\n T extends Record<string, never>\n ? ExtraOutputs\n : { [K in keyof T]: DeepInput<T[K]> } & ExtraOutputs<TArgName>\n\nexport interface UnitContext<\n TArgs extends Record<string, ArgumentValue>,\n TInputs extends Record<string, unknown>,\n TOutputs extends Record<string, unknown>,\n TSecrets extends Record<string, ArgumentValue>,\n> {\n args: TArgs\n instanceId: string\n type: string\n name: string\n secrets: Output<TSecrets>\n\n inputs: {\n [K in keyof TInputs]: undefined extends TInputs[K]\n ? Output<NonNullable<TInputs[K]>> | undefined\n : Output<TInputs[K]>\n }\n\n invokedTriggers: InstanceTriggerInvocation[]\n\n outputs(\n this: void,\n outputs?: OutputMapToDeepInputMap<TOutputs, keyof TArgs & string>,\n ): Promise<unknown>\n}\n\ntype InputSpecToValue<T extends ComponentInputSpec> = T[2] extends true\n ? Static<T[0][\"schema\"]>[]\n : T[1] extends true\n ? Static<T[0][\"schema\"]>\n : Static<T[0][\"schema\"]> | undefined\n\ntype InputSpecMapToValueMap<T extends Record<string, ComponentInputSpec>> =\n T extends Record<string, never>\n ? Record<string, never>\n : { [K in keyof T]: InputSpecToValue<T[K]> }\n\nconst stackRefMap = new Map<string, StackReference>()\nconst [projectId, instanceName] = getStack().split(\"_\")\n\nlet instanceId: string | undefined\n\nexport function getUnitInstanceId(): string {\n if (!instanceId) {\n throw new Error(\"Instance id is not set. Did you call 'forUnit' function?\")\n }\n\n return instanceId\n}\n\nexport function getUnitInstanceName(): string {\n return instanceName\n}\n\nfunction getStackRef(input: InstanceInput) {\n const [instanceType, instanceName] = parseInstanceId(input.instanceId)\n const key = `organization/${instanceType}/${projectId}_${instanceName}`\n\n if (!stackRefMap.has(key)) {\n stackRefMap.set(key, new StackReference(key))\n }\n\n return stackRefMap.get(key)!\n}\n\nfunction getOutput(unit: Unit, input: ComponentInput, refs: InstanceInput[]) {\n const entity = unit.entities.get(input.type)\n if (!entity) {\n throw new Error(`Entity '${input.type}' not found in the unit '${unit.model.type}'.`)\n }\n\n const _getOutput = (ref: InstanceInput) => {\n const value = getStackRef(ref).requireOutput(ref.output)\n\n return value.apply(value => {\n let schema = entity.schema\n\n if (input.multiple) {\n schema = Type.Union([schema, Type.Array(schema)])\n }\n\n if (!ajv.validate(schema, value)) {\n throw new Error(`Invalid output for '${input.type}': ${ajv.errorsText()}`)\n }\n\n if (Array.isArray(value)) {\n return value as unknown\n }\n\n return input.multiple ? [value] : value\n })\n }\n\n const values = output(refs.map(ref => _getOutput(ref))).apply(values => values.flat())\n\n if (!input.multiple) {\n return values.apply(values => values[0])\n }\n\n return values\n}\n\nfunction isAnyOfSchema(schema: ArgumentValueSchema, itemType: string): boolean {\n if (schema.anyOf) {\n return Object.values(schema.anyOf).every(schema =>\n isAnyOfSchema(schema as ArgumentValueSchema, itemType),\n )\n }\n\n return schema.type === itemType\n}\n\nfunction isStringSchema(schema: ArgumentValueSchema): boolean {\n if (schema.type === \"string\") {\n return true\n }\n\n if (isAnyOfSchema(schema, \"string\")) {\n return true\n }\n\n return false\n}\n\nfunction isNumberSchema(schema: ArgumentValueSchema): boolean {\n if (schema.type === \"number\") {\n return true\n }\n\n if (isAnyOfSchema(schema, \"number\")) {\n return true\n }\n\n return false\n}\n\nfunction isBooleanSchema(schema: ArgumentValueSchema): boolean {\n if (schema.type === \"boolean\") {\n return true\n }\n\n if (isAnyOfSchema(schema, \"boolean\")) {\n return true\n }\n\n return false\n}\n\nexport function forUnit<\n TArgs extends Record<string, ArgumentValue>,\n TInputs extends Record<string, ComponentInputSpec>,\n TOutputs extends Record<string, ComponentInputSpec>,\n TSecrets extends Record<string, ArgumentValue>,\n>(\n unit: Unit<TArgs, TInputs, TOutputs, TSecrets>,\n): UnitContext<\n //\n TArgs,\n InputSpecMapToValueMap<TInputs>,\n InputSpecMapToValueMap<TOutputs>,\n TSecrets\n> {\n const config = new Config()\n\n const args = mapValues(unit.model.args, (arg, argName) => {\n switch (true) {\n case isStringSchema(arg.schema): {\n return arg.required ? config.require(argName) : config.get(argName)\n }\n case isNumberSchema(arg.schema): {\n return arg.required ? config.requireNumber(argName) : config.getNumber(argName)\n }\n case isBooleanSchema(arg.schema): {\n return arg.required ? config.requireBoolean(argName) : config.getBoolean(argName)\n }\n default: {\n const value = arg.required ? config.requireObject(argName) : config.getObject(argName)\n if (value === undefined) return undefined\n\n if (!ajv.validate(arg.schema, value)) {\n throw new Error(`Invalid config for '${argName}': ${ajv.errorsText()}`)\n }\n\n return value\n }\n }\n }) as TArgs\n\n const secrets = output(\n mapValues(unit.model.secrets, (secret, secretName) => {\n switch (true) {\n case isStringSchema(secret.schema): {\n return secret.required ? config.requireSecret(secretName) : config.getSecret(secretName)\n }\n case isNumberSchema(secret.schema): {\n return secret.required\n ? config.requireSecretNumber(secretName)\n : config.getSecretNumber(secretName)\n }\n case isBooleanSchema(secret.schema): {\n return secret.required\n ? config.requireSecretBoolean(secretName)\n : config.getSecretBoolean(secretName)\n }\n default: {\n const value = secret.required\n ? config.requireSecretObject(secretName)\n : config.getSecretObject(secretName)\n\n if (!ajv.validate(secret.schema, value)) {\n throw new Error(`Invalid secret for '${secretName}': ${ajv.errorsText()}`)\n }\n\n return value\n }\n }\n }),\n ) as unknown as Output<TSecrets>\n\n const inputs = mapValues(unit.model.inputs, (input, inputName) => {\n const value = input.required\n ? config.requireObject<InstanceInput[]>(`input.${inputName}`)\n : config.getObject<InstanceInput[]>(`input.${inputName}`)\n\n if (!value) {\n if (input.multiple) {\n return output([])\n }\n\n return undefined\n }\n\n return getOutput(unit as unknown as Unit, input, value)\n })\n\n const type = unit.model.type\n instanceId = getInstanceId(type, instanceName)\n\n return {\n args,\n instanceId,\n type,\n name: instanceName,\n secrets,\n inputs: inputs as any,\n invokedTriggers: config.getObject<InstanceTriggerInvocation[]>(\"$invokedTriggers\") ?? [],\n\n outputs: async (outputs: any = {}) => {\n const result: any = mapValues(outputs, (outputValue, outputName) => {\n if (outputName === \"$status\") {\n return output(outputValue).apply(mapStatus)\n }\n\n if (outputName === \"$pages\") {\n return output(outputValue).apply(mapPages)\n }\n\n if (outputName === \"$files\") {\n return output(outputValue).apply(mapFiles)\n }\n\n if (outputName === \"$terminals\") {\n return output(outputValue).apply(mapTerminals)\n }\n\n if (outputName === \"$triggers\") {\n return output(outputValue).apply(mapTriggers)\n }\n\n if (outputName.startsWith(\"$\")) {\n throw new Error(`Unknown extra output '${outputName}'.`)\n }\n\n const outputModel = unit.model.outputs[outputName]\n if (!outputModel) {\n throw new Error(`Output '${outputName}' not found in the unit '${unit.model.type}'.`)\n }\n\n const entity = unit.entities.get(outputModel.type)\n if (!entity) {\n throw new Error(\n `Entity '${outputModel.type}' not found in the unit '${unit.model.type}'.`,\n )\n }\n\n return output(outputValue).apply(value => {\n if (value === undefined) {\n if (outputModel.required) {\n throw new Error(`Output '${outputName}' is required.`)\n }\n\n return undefined\n }\n\n if (!ajv.validate(entity.schema, value)) {\n throw new Error(`Invalid output for '${outputModel.type}': ${ajv.errorsText()}`)\n }\n\n return value\n })\n }) as Record<string, Output<unknown>> & ExtraOutputs\n\n await Promise.all(Object.values(result).map(o => outputToPromise(o)))\n\n if (Object.keys(createdSecrets).length > 0) {\n result.$secrets = createdSecrets\n }\n\n return result\n },\n }\n}\n\nexport type EntityValue<T extends Entity> = Static<T[\"schema\"]>\nexport type EntityInput<T extends Entity> = Output<EntityValue<T>>\n\nfunction outputToPromise(o: unknown): Promise<unknown> {\n return new Promise(resolve => (output(o) as Output<unknown>).apply(resolve))\n}\n\nfunction mapStatus(status: Unwrap<ExtraOutputs[\"$status\"]>): StatusField[] {\n if (!status) {\n return []\n }\n\n if (Array.isArray(status)) {\n return status.filter(field => !!field?.value) as StatusField[]\n }\n\n return Object.entries(status)\n .map(([name, field]) => {\n if (!field) {\n return undefined\n }\n\n if (typeof field === \"string\") {\n return { name, value: field }\n }\n\n return { ...(field as StatusField), name }\n })\n .filter(field => !!field?.value) as StatusField[]\n}\n\nfunction mapPages(pages: Unwrap<ExtraOutputs[\"$pages\"]>): InstancePage[] {\n if (!pages) {\n return []\n }\n\n if (Array.isArray(pages)) {\n return pages.filter(page => !!page)\n }\n\n return Object.entries(pages)\n .filter(([, page]) => !!page)\n .map(([name, page]) => ({ ...page!, name }))\n}\n\nexport function fileFromString(\n name: string,\n content: string,\n contentType = \"text/plain\",\n isSecret = false,\n): InstanceFile {\n return {\n meta: {\n name,\n contentType,\n size: Buffer.byteLength(content, \"utf8\"),\n },\n content: isSecret ? secret(content) : content,\n }\n}\n\nexport function fileFromBuffer(\n name: string,\n content: Buffer,\n contentType = \"application/octet-stream\",\n isSecret = false,\n): InstanceFile {\n return {\n meta: {\n name,\n contentType,\n size: content.byteLength,\n isBinary: true,\n },\n content: isSecret ? secret(content.toString(\"base64\")) : content.toString(\"base64\"),\n }\n}\n\nfunction mapFiles(files: Unwrap<ExtraOutputs[\"$files\"]>): InstanceFile[] {\n return files?.filter(file => !!file) ?? []\n}\n\nfunction mapTerminals(terminals: Unwrap<ExtraOutputs[\"$terminals\"]>): InstanceTerminal[] {\n if (!terminals) {\n return []\n }\n\n if (!Array.isArray(terminals)) {\n terminals = Object.entries(terminals).map(([name, terminal]) => {\n if (!terminal) {\n return undefined\n }\n\n return { ...terminal, name }\n })\n }\n\n return terminals\n .filter(terminal => !!terminal)\n .map(terminal => {\n if (!terminal.files) {\n return terminal\n }\n\n return {\n ...terminal,\n\n files: pipe(\n terminal.files,\n mapValues(file => {\n if (typeof file === \"string\") {\n return { content: file }\n }\n\n return file\n }),\n pickBy(value => !!value?.content),\n ),\n }\n })\n}\n\nfunction mapTriggers(triggers: Unwrap<ExtraOutputs[\"$triggers\"]>): InstanceTrigger[] {\n if (!triggers) {\n return []\n }\n\n if (Array.isArray(triggers)) {\n return triggers.filter(trigger => !!trigger)\n }\n\n return Object.entries(triggers)\n .filter(([, trigger]) => !!trigger)\n .map(([name, trigger]) => ({ ...(trigger as InstanceTrigger), name }))\n}\n","import { secret, type Input, type Output } from \"@pulumi/pulumi\"\n\nexport const createdSecrets: Record<string, Output<unknown>> = {}\n\nexport function getOrCreateSecret<\n TSecrets extends Record<string, unknown>,\n TResult extends TSecrets[keyof TSecrets],\n>(secrets: Output<TSecrets>, key: keyof TSecrets, create: () => Input<TResult>): Output<TResult> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n return secrets[key as any].apply(value => {\n if (value !== undefined) {\n // if the secret is accessed via \"getOrCreateSecret\" with assume it automatically created (even if it was not)\n // in order to provide stable stack outputs\n createdSecrets[key as string] = value as Output<unknown>\n return value as TResult\n }\n\n const secretValue = createdSecrets[key as string] ?? secret(create())\n createdSecrets[key as string] = secretValue\n\n return secretValue\n }) as Output<TResult>\n}\n","import { type Input, type Unwrap, type Output, output, all } from \"@pulumi/pulumi\"\n\n/**\n * The input type for an array of inputs.\n * The same as `Input<Input<T>[]>`, but more readable.\n */\nexport type InputArray<T> = Input<Input<T>[]>\n\n/**\n * The input type for a map of inputs.\n * The same as `Input<Record<string, Input<T>>>`, but more readable.\n */\nexport type InputMap<T> = Input<Readonly<Record<string, Input<T>>>>\n\n/**\n * The input or input array type for a value.\n */\nexport type InputOrArray<T> = Input<T> | InputArray<T>\n\n/**\n * The input of inputs of inputs of inputs, so you got the idea.\n */\nexport type DeepInput<T> = [T] extends [Record<string, unknown> | undefined]\n ? [T] extends [infer U | undefined]\n ? Input<{ [K in keyof U]: DeepInput<U[K]> } | undefined>\n : Input<{ [K in keyof T]: DeepInput<T[K]> }>\n : [T] extends [Array<unknown> | undefined]\n ? [T] extends [(infer U)[] | undefined]\n ? Input<DeepInput<U>[] | undefined>\n : Input<DeepInput<T>[]>\n : Input<T>\n\n/**\n * Merges the given array of `InputOrArray` values into a single flat output array.\n *\n * @param values The values to merge.\n * @returns The merged output array.\n */\nexport function flattenInputs<T>(...values: (InputOrArray<T> | undefined)[]): Output<T[]> {\n return all(values).apply(allValues => {\n const result: T[] = []\n for (const value of allValues) {\n if (Array.isArray(value)) {\n result.push(...(value as T[]))\n } else if (value) {\n result.push(value as T)\n }\n }\n return result\n })\n}\n\n/**\n * Maps each element of an input array to a new value.\n * Produces an output array with the same length.\n *\n * @param array The input array.\n * @param fn The mapping function.\n * @returns The output array.\n */\nexport function mapInputs<T, U>(\n array: InputArray<T>,\n fn: (v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U,\n): Output<U[]> {\n return output(array).apply(array => {\n return array?.map((v, index) => fn(v as Unwrap<T>, index, array as Unwrap<T>[])) ?? []\n })\n}\n\nexport function flatMapInput<T, U>(\n v1: InputOrArray<T>,\n v2: InputOrArray<T>,\n fn: (v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U,\n): Output<U[]>\n\nexport function flatMapInput<T, U>(\n v1: InputOrArray<T>,\n v2: InputOrArray<T>,\n v3: InputOrArray<T>,\n fn: (v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U,\n): Output<U[]>\n\n/**\n * Merges the given array of `InputOrArray` values into a single flat output array and maps each element to a new value.\n *\n * @param values The values to merge.\n * @param fn The mapping function.\n */\nexport function flatMapInput<T, U>(\n ...args: (InputOrArray<T> | ((v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U))[]\n): Output<U[]> {\n const fn = args.pop() as (v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U\n const values = args as InputOrArray<T>[]\n\n return mapInputs(flattenInputs(...values), fn)\n}\n\n/**\n * Map an optional value to another optional value.\n *\n * @param input The input value.\n * @param func The function to apply to the input value.\n * @returns The output value, or `undefined` if the input value is `undefined`.\n */\nexport function mapOptional<T, U>(input: T | undefined, func: (value: T) => U): U | undefined {\n if (input === undefined) {\n return undefined\n }\n\n return func(input)\n}\n\nexport function toPromise<T>(input: Input<T>): Promise<Unwrap<T>> {\n return new Promise(resolve => output(input).apply(resolve))\n}\n\nexport function singleton<T>(factory: () => T): () => T {\n let instance: T | undefined\n return () => {\n if (instance === undefined) {\n instance = factory()\n }\n\n return instance\n }\n}\n\nexport function providerFactory<TInput>(\n factory: (name: string) => TInput,\n): (name: string) => TInput {\n const instances = new Map<string, TInput>()\n return name => {\n if (!instances.has(name)) {\n instances.set(name, factory(name))\n }\n\n return instances.get(name)!\n }\n}\n\nexport function mergeInputObjects<\n T1 extends Record<string, unknown>,\n T2 extends Record<string, unknown>,\n>(obj1: Input<T1 | undefined> | undefined, obj2: Input<T2 | undefined> | undefined): Output<T1 & T2>\n\nexport function mergeInputObjects<\n T1 extends Record<string, unknown>,\n T2 extends Record<string, unknown>,\n T3 extends Record<string, unknown>,\n>(\n obj1: Input<T1 | undefined> | undefined,\n obj2: Input<T2 | undefined> | undefined,\n obj3: Input<T3 | undefined> | undefined,\n): Output<T1 & T2 & T3>\n\n/**\n * Merges the given input objects into a single output object.\n *\n * @param objects The input objects.\n * @returns The output object.\n */\nexport function mergeInputObjects(\n ...objects: Input<Record<string, unknown>>[]\n): Output<Record<string, unknown>> {\n return output(objects).apply(array => {\n return Object.assign({}, ...array) as Record<string, unknown>\n })\n}\n\nexport function normalize<T>(item: T | undefined, collection: T[] | undefined): T[] {\n if (item && collection) {\n return [item, ...collection]\n }\n\n if (item) {\n return [item]\n }\n\n return collection ?? []\n}\n\nexport function apply<T, U>(fn: (value: Unwrap<T>) => U): (input: Input<T>) => Output<U> {\n return input => output(input).apply(fn)\n}\n"],"mappings":"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","names":["secret","instanceName","value","values","schema","secret","output","array"]}
package/package.json CHANGED
@@ -1,34 +1,33 @@
1
1
  {
2
2
  "name": "@highstate/pulumi",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "type": "module",
5
- "module": "dist/index.mjs",
6
- "types": "dist/index.d.ts",
7
5
  "files": [
8
- "dist"
6
+ "dist",
7
+ "src"
9
8
  ],
10
9
  "exports": {
11
10
  ".": {
12
- "types": "./dist/index.d.ts",
13
- "default": "./dist/index.mjs"
11
+ "types": "./src/index.ts",
12
+ "default": "./dist/index.js"
14
13
  }
15
14
  },
16
15
  "publishConfig": {
17
16
  "access": "public"
18
17
  },
19
18
  "scripts": {
20
- "build": "pkgroll --tsconfig=tsconfig.build.json"
19
+ "build": "highstate build"
21
20
  },
22
21
  "dependencies": {
23
- "@highstate/contract": "^0.7.2",
24
- "@pulumi/pulumi": "^3.152.0",
22
+ "@highstate/contract": "^0.7.4",
23
+ "@pulumi/pulumi": "^3.163.0",
25
24
  "@sinclair/typebox": "^0.34.11",
26
25
  "ajv": "^8.17.1",
27
26
  "import-meta-resolve": "^4.1.0",
28
27
  "remeda": "^2.21.0"
29
28
  },
30
29
  "devDependencies": {
31
- "pkgroll": "^2.5.1"
30
+ "@highstate/cli": "^0.7.4"
32
31
  },
33
- "gitHead": "e177535015e0fa3c74ae8ddc0bc6d31b191d2c54"
32
+ "gitHead": "c482cdf650746f6814122602d65bf5b842a2bc2c"
34
33
  }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from "@pulumi/pulumi"
2
+ export * from "./unit"
3
+ export * from "./utils"
4
+ export { getOrCreateSecret } from "./secret"
package/src/secret.ts ADDED
@@ -0,0 +1,23 @@
1
+ import { secret, type Input, type Output } from "@pulumi/pulumi"
2
+
3
+ export const createdSecrets: Record<string, Output<unknown>> = {}
4
+
5
+ export function getOrCreateSecret<
6
+ TSecrets extends Record<string, unknown>,
7
+ TResult extends TSecrets[keyof TSecrets],
8
+ >(secrets: Output<TSecrets>, key: keyof TSecrets, create: () => Input<TResult>): Output<TResult> {
9
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
10
+ return secrets[key as any].apply(value => {
11
+ if (value !== undefined) {
12
+ // if the secret is accessed via "getOrCreateSecret" with assume it automatically created (even if it was not)
13
+ // in order to provide stable stack outputs
14
+ createdSecrets[key as string] = value as Output<unknown>
15
+ return value as TResult
16
+ }
17
+
18
+ const secretValue = createdSecrets[key as string] ?? secret(create())
19
+ createdSecrets[key as string] = secretValue
20
+
21
+ return secretValue
22
+ }) as Output<TResult>
23
+ }
package/src/unit.ts ADDED
@@ -0,0 +1,574 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
4
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
5
+ /* eslint-disable @typescript-eslint/no-explicit-any */
6
+
7
+ import type { DeepInput, InputArray, InputMap } from "./utils"
8
+ import {
9
+ type ArgumentValue,
10
+ type ComponentInputSpec,
11
+ type Entity,
12
+ type Unit,
13
+ type ComponentInput,
14
+ type InstanceInput,
15
+ parseInstanceId,
16
+ type ArgumentValueSchema,
17
+ getInstanceId,
18
+ } from "@highstate/contract"
19
+ import { Type, type Static } from "@sinclair/typebox"
20
+ import { mapValues, pickBy, pipe } from "remeda"
21
+ import {
22
+ Config,
23
+ getStack,
24
+ Output,
25
+ output,
26
+ secret,
27
+ StackReference,
28
+ type Input,
29
+ type Unwrap,
30
+ } from "@pulumi/pulumi"
31
+ import { Ajv } from "ajv"
32
+ import { createdSecrets } from "./secret"
33
+
34
+ const ajv = new Ajv()
35
+
36
+ export type InstanceTerminalFile = {
37
+ content: Input<string | undefined>
38
+ mode?: Input<number | undefined>
39
+ isBinary?: Input<boolean>
40
+ }
41
+
42
+ export type InstanceTerminal = {
43
+ name: Input<string>
44
+ title: Input<string>
45
+ description?: Input<string>
46
+ image: Input<string>
47
+ command: InputArray<string>
48
+ cwd?: Input<string | undefined>
49
+ env?: InputMap<string | undefined>
50
+ files?: InputMap<InstanceTerminalFile | string | undefined>
51
+ }
52
+
53
+ export type StatusField<TArgName extends string = string> = {
54
+ name: Input<string>
55
+ value?: Input<string | undefined>
56
+ displayName?: Input<string | undefined>
57
+ sensitive?: Input<boolean | undefined>
58
+ url?: Input<string | undefined>
59
+ complementaryTo?: Input<TArgName | undefined>
60
+ }
61
+
62
+ export type InstanceFileMeta = {
63
+ name: Input<string>
64
+ contentType: Input<string>
65
+ isBinary?: Input<boolean>
66
+ size: Input<number>
67
+ }
68
+
69
+ export type InstanceFile = {
70
+ meta: Input<InstanceFileMeta>
71
+ content: Input<string>
72
+ }
73
+
74
+ export type InstancePageBlock =
75
+ | { type: "markdown"; content: Input<string> }
76
+ | { type: "qr"; content: Input<string>; showContent?: boolean; language?: string }
77
+ | { type: "file"; fileMeta: Input<InstanceFileMeta> }
78
+
79
+ export type InstancePage = {
80
+ name: Input<string>
81
+ title: Input<string>
82
+ content: InputArray<InstancePageBlock>
83
+ }
84
+
85
+ export type InstanceTriggerSpec =
86
+ | {
87
+ type: "before-destroy"
88
+ }
89
+ | {
90
+ type: "schedule"
91
+ schedule: string
92
+ }
93
+
94
+ export type InstanceTrigger = {
95
+ name: Input<string>
96
+ title: Input<string>
97
+ description?: Input<string>
98
+ spec: Input<InstanceTriggerSpec>
99
+ }
100
+
101
+ export type ExtraOutputs<TArgName extends string = string> = {
102
+ $status?:
103
+ | InputMap<Omit<StatusField<TArgName>, "name"> | string | undefined>
104
+ | InputArray<StatusField<TArgName> | undefined>
105
+
106
+ $terminals?:
107
+ | InputMap<Omit<InstanceTerminal, "name"> | undefined>
108
+ | InputArray<InstanceTerminal | undefined>
109
+
110
+ $pages?: InputMap<Omit<InstancePage, "name"> | undefined> | InputArray<InstancePage | undefined>
111
+ $files?: InputArray<InstanceFile | undefined>
112
+
113
+ $triggers?:
114
+ | InputMap<Omit<InstanceTrigger, "name"> | undefined>
115
+ | InputArray<InstanceTrigger | undefined>
116
+ }
117
+
118
+ export type InstanceTriggerInvocation = {
119
+ name: string
120
+ }
121
+
122
+ type OutputMapToDeepInputMap<T extends Record<string, unknown>, TArgName extends string> =
123
+ T extends Record<string, never>
124
+ ? ExtraOutputs
125
+ : { [K in keyof T]: DeepInput<T[K]> } & ExtraOutputs<TArgName>
126
+
127
+ export interface UnitContext<
128
+ TArgs extends Record<string, ArgumentValue>,
129
+ TInputs extends Record<string, unknown>,
130
+ TOutputs extends Record<string, unknown>,
131
+ TSecrets extends Record<string, ArgumentValue>,
132
+ > {
133
+ args: TArgs
134
+ instanceId: string
135
+ type: string
136
+ name: string
137
+ secrets: Output<TSecrets>
138
+
139
+ inputs: {
140
+ [K in keyof TInputs]: undefined extends TInputs[K]
141
+ ? Output<NonNullable<TInputs[K]>> | undefined
142
+ : Output<TInputs[K]>
143
+ }
144
+
145
+ invokedTriggers: InstanceTriggerInvocation[]
146
+
147
+ outputs(
148
+ this: void,
149
+ outputs?: OutputMapToDeepInputMap<TOutputs, keyof TArgs & string>,
150
+ ): Promise<unknown>
151
+ }
152
+
153
+ type InputSpecToValue<T extends ComponentInputSpec> = T[2] extends true
154
+ ? Static<T[0]["schema"]>[]
155
+ : T[1] extends true
156
+ ? Static<T[0]["schema"]>
157
+ : Static<T[0]["schema"]> | undefined
158
+
159
+ type InputSpecMapToValueMap<T extends Record<string, ComponentInputSpec>> =
160
+ T extends Record<string, never>
161
+ ? Record<string, never>
162
+ : { [K in keyof T]: InputSpecToValue<T[K]> }
163
+
164
+ const stackRefMap = new Map<string, StackReference>()
165
+ const [projectId, instanceName] = getStack().split("_")
166
+
167
+ let instanceId: string | undefined
168
+
169
+ export function getUnitInstanceId(): string {
170
+ if (!instanceId) {
171
+ throw new Error("Instance id is not set. Did you call 'forUnit' function?")
172
+ }
173
+
174
+ return instanceId
175
+ }
176
+
177
+ export function getUnitInstanceName(): string {
178
+ return instanceName
179
+ }
180
+
181
+ function getStackRef(input: InstanceInput) {
182
+ const [instanceType, instanceName] = parseInstanceId(input.instanceId)
183
+ const key = `organization/${instanceType}/${projectId}_${instanceName}`
184
+
185
+ if (!stackRefMap.has(key)) {
186
+ stackRefMap.set(key, new StackReference(key))
187
+ }
188
+
189
+ return stackRefMap.get(key)!
190
+ }
191
+
192
+ function getOutput(unit: Unit, input: ComponentInput, refs: InstanceInput[]) {
193
+ const entity = unit.entities.get(input.type)
194
+ if (!entity) {
195
+ throw new Error(`Entity '${input.type}' not found in the unit '${unit.model.type}'.`)
196
+ }
197
+
198
+ const _getOutput = (ref: InstanceInput) => {
199
+ const value = getStackRef(ref).requireOutput(ref.output)
200
+
201
+ return value.apply(value => {
202
+ let schema = entity.schema
203
+
204
+ if (input.multiple) {
205
+ schema = Type.Union([schema, Type.Array(schema)])
206
+ }
207
+
208
+ if (!ajv.validate(schema, value)) {
209
+ throw new Error(`Invalid output for '${input.type}': ${ajv.errorsText()}`)
210
+ }
211
+
212
+ if (Array.isArray(value)) {
213
+ return value as unknown
214
+ }
215
+
216
+ return input.multiple ? [value] : value
217
+ })
218
+ }
219
+
220
+ const values = output(refs.map(ref => _getOutput(ref))).apply(values => values.flat())
221
+
222
+ if (!input.multiple) {
223
+ return values.apply(values => values[0])
224
+ }
225
+
226
+ return values
227
+ }
228
+
229
+ function isAnyOfSchema(schema: ArgumentValueSchema, itemType: string): boolean {
230
+ if (schema.anyOf) {
231
+ return Object.values(schema.anyOf).every(schema =>
232
+ isAnyOfSchema(schema as ArgumentValueSchema, itemType),
233
+ )
234
+ }
235
+
236
+ return schema.type === itemType
237
+ }
238
+
239
+ function isStringSchema(schema: ArgumentValueSchema): boolean {
240
+ if (schema.type === "string") {
241
+ return true
242
+ }
243
+
244
+ if (isAnyOfSchema(schema, "string")) {
245
+ return true
246
+ }
247
+
248
+ return false
249
+ }
250
+
251
+ function isNumberSchema(schema: ArgumentValueSchema): boolean {
252
+ if (schema.type === "number") {
253
+ return true
254
+ }
255
+
256
+ if (isAnyOfSchema(schema, "number")) {
257
+ return true
258
+ }
259
+
260
+ return false
261
+ }
262
+
263
+ function isBooleanSchema(schema: ArgumentValueSchema): boolean {
264
+ if (schema.type === "boolean") {
265
+ return true
266
+ }
267
+
268
+ if (isAnyOfSchema(schema, "boolean")) {
269
+ return true
270
+ }
271
+
272
+ return false
273
+ }
274
+
275
+ export function forUnit<
276
+ TArgs extends Record<string, ArgumentValue>,
277
+ TInputs extends Record<string, ComponentInputSpec>,
278
+ TOutputs extends Record<string, ComponentInputSpec>,
279
+ TSecrets extends Record<string, ArgumentValue>,
280
+ >(
281
+ unit: Unit<TArgs, TInputs, TOutputs, TSecrets>,
282
+ ): UnitContext<
283
+ //
284
+ TArgs,
285
+ InputSpecMapToValueMap<TInputs>,
286
+ InputSpecMapToValueMap<TOutputs>,
287
+ TSecrets
288
+ > {
289
+ const config = new Config()
290
+
291
+ const args = mapValues(unit.model.args, (arg, argName) => {
292
+ switch (true) {
293
+ case isStringSchema(arg.schema): {
294
+ return arg.required ? config.require(argName) : config.get(argName)
295
+ }
296
+ case isNumberSchema(arg.schema): {
297
+ return arg.required ? config.requireNumber(argName) : config.getNumber(argName)
298
+ }
299
+ case isBooleanSchema(arg.schema): {
300
+ return arg.required ? config.requireBoolean(argName) : config.getBoolean(argName)
301
+ }
302
+ default: {
303
+ const value = arg.required ? config.requireObject(argName) : config.getObject(argName)
304
+ if (value === undefined) return undefined
305
+
306
+ if (!ajv.validate(arg.schema, value)) {
307
+ throw new Error(`Invalid config for '${argName}': ${ajv.errorsText()}`)
308
+ }
309
+
310
+ return value
311
+ }
312
+ }
313
+ }) as TArgs
314
+
315
+ const secrets = output(
316
+ mapValues(unit.model.secrets, (secret, secretName) => {
317
+ switch (true) {
318
+ case isStringSchema(secret.schema): {
319
+ return secret.required ? config.requireSecret(secretName) : config.getSecret(secretName)
320
+ }
321
+ case isNumberSchema(secret.schema): {
322
+ return secret.required
323
+ ? config.requireSecretNumber(secretName)
324
+ : config.getSecretNumber(secretName)
325
+ }
326
+ case isBooleanSchema(secret.schema): {
327
+ return secret.required
328
+ ? config.requireSecretBoolean(secretName)
329
+ : config.getSecretBoolean(secretName)
330
+ }
331
+ default: {
332
+ const value = secret.required
333
+ ? config.requireSecretObject(secretName)
334
+ : config.getSecretObject(secretName)
335
+
336
+ if (!ajv.validate(secret.schema, value)) {
337
+ throw new Error(`Invalid secret for '${secretName}': ${ajv.errorsText()}`)
338
+ }
339
+
340
+ return value
341
+ }
342
+ }
343
+ }),
344
+ ) as unknown as Output<TSecrets>
345
+
346
+ const inputs = mapValues(unit.model.inputs, (input, inputName) => {
347
+ const value = input.required
348
+ ? config.requireObject<InstanceInput[]>(`input.${inputName}`)
349
+ : config.getObject<InstanceInput[]>(`input.${inputName}`)
350
+
351
+ if (!value) {
352
+ if (input.multiple) {
353
+ return output([])
354
+ }
355
+
356
+ return undefined
357
+ }
358
+
359
+ return getOutput(unit as unknown as Unit, input, value)
360
+ })
361
+
362
+ const type = unit.model.type
363
+ instanceId = getInstanceId(type, instanceName)
364
+
365
+ return {
366
+ args,
367
+ instanceId,
368
+ type,
369
+ name: instanceName,
370
+ secrets,
371
+ inputs: inputs as any,
372
+ invokedTriggers: config.getObject<InstanceTriggerInvocation[]>("$invokedTriggers") ?? [],
373
+
374
+ outputs: async (outputs: any = {}) => {
375
+ const result: any = mapValues(outputs, (outputValue, outputName) => {
376
+ if (outputName === "$status") {
377
+ return output(outputValue).apply(mapStatus)
378
+ }
379
+
380
+ if (outputName === "$pages") {
381
+ return output(outputValue).apply(mapPages)
382
+ }
383
+
384
+ if (outputName === "$files") {
385
+ return output(outputValue).apply(mapFiles)
386
+ }
387
+
388
+ if (outputName === "$terminals") {
389
+ return output(outputValue).apply(mapTerminals)
390
+ }
391
+
392
+ if (outputName === "$triggers") {
393
+ return output(outputValue).apply(mapTriggers)
394
+ }
395
+
396
+ if (outputName.startsWith("$")) {
397
+ throw new Error(`Unknown extra output '${outputName}'.`)
398
+ }
399
+
400
+ const outputModel = unit.model.outputs[outputName]
401
+ if (!outputModel) {
402
+ throw new Error(`Output '${outputName}' not found in the unit '${unit.model.type}'.`)
403
+ }
404
+
405
+ const entity = unit.entities.get(outputModel.type)
406
+ if (!entity) {
407
+ throw new Error(
408
+ `Entity '${outputModel.type}' not found in the unit '${unit.model.type}'.`,
409
+ )
410
+ }
411
+
412
+ return output(outputValue).apply(value => {
413
+ if (value === undefined) {
414
+ if (outputModel.required) {
415
+ throw new Error(`Output '${outputName}' is required.`)
416
+ }
417
+
418
+ return undefined
419
+ }
420
+
421
+ if (!ajv.validate(entity.schema, value)) {
422
+ throw new Error(`Invalid output for '${outputModel.type}': ${ajv.errorsText()}`)
423
+ }
424
+
425
+ return value
426
+ })
427
+ }) as Record<string, Output<unknown>> & ExtraOutputs
428
+
429
+ await Promise.all(Object.values(result).map(o => outputToPromise(o)))
430
+
431
+ if (Object.keys(createdSecrets).length > 0) {
432
+ result.$secrets = createdSecrets
433
+ }
434
+
435
+ return result
436
+ },
437
+ }
438
+ }
439
+
440
+ export type EntityValue<T extends Entity> = Static<T["schema"]>
441
+ export type EntityInput<T extends Entity> = Output<EntityValue<T>>
442
+
443
+ function outputToPromise(o: unknown): Promise<unknown> {
444
+ return new Promise(resolve => (output(o) as Output<unknown>).apply(resolve))
445
+ }
446
+
447
+ function mapStatus(status: Unwrap<ExtraOutputs["$status"]>): StatusField[] {
448
+ if (!status) {
449
+ return []
450
+ }
451
+
452
+ if (Array.isArray(status)) {
453
+ return status.filter(field => !!field?.value) as StatusField[]
454
+ }
455
+
456
+ return Object.entries(status)
457
+ .map(([name, field]) => {
458
+ if (!field) {
459
+ return undefined
460
+ }
461
+
462
+ if (typeof field === "string") {
463
+ return { name, value: field }
464
+ }
465
+
466
+ return { ...(field as StatusField), name }
467
+ })
468
+ .filter(field => !!field?.value) as StatusField[]
469
+ }
470
+
471
+ function mapPages(pages: Unwrap<ExtraOutputs["$pages"]>): InstancePage[] {
472
+ if (!pages) {
473
+ return []
474
+ }
475
+
476
+ if (Array.isArray(pages)) {
477
+ return pages.filter(page => !!page)
478
+ }
479
+
480
+ return Object.entries(pages)
481
+ .filter(([, page]) => !!page)
482
+ .map(([name, page]) => ({ ...page!, name }))
483
+ }
484
+
485
+ export function fileFromString(
486
+ name: string,
487
+ content: string,
488
+ contentType = "text/plain",
489
+ isSecret = false,
490
+ ): InstanceFile {
491
+ return {
492
+ meta: {
493
+ name,
494
+ contentType,
495
+ size: Buffer.byteLength(content, "utf8"),
496
+ },
497
+ content: isSecret ? secret(content) : content,
498
+ }
499
+ }
500
+
501
+ export function fileFromBuffer(
502
+ name: string,
503
+ content: Buffer,
504
+ contentType = "application/octet-stream",
505
+ isSecret = false,
506
+ ): InstanceFile {
507
+ return {
508
+ meta: {
509
+ name,
510
+ contentType,
511
+ size: content.byteLength,
512
+ isBinary: true,
513
+ },
514
+ content: isSecret ? secret(content.toString("base64")) : content.toString("base64"),
515
+ }
516
+ }
517
+
518
+ function mapFiles(files: Unwrap<ExtraOutputs["$files"]>): InstanceFile[] {
519
+ return files?.filter(file => !!file) ?? []
520
+ }
521
+
522
+ function mapTerminals(terminals: Unwrap<ExtraOutputs["$terminals"]>): InstanceTerminal[] {
523
+ if (!terminals) {
524
+ return []
525
+ }
526
+
527
+ if (!Array.isArray(terminals)) {
528
+ terminals = Object.entries(terminals).map(([name, terminal]) => {
529
+ if (!terminal) {
530
+ return undefined
531
+ }
532
+
533
+ return { ...terminal, name }
534
+ })
535
+ }
536
+
537
+ return terminals
538
+ .filter(terminal => !!terminal)
539
+ .map(terminal => {
540
+ if (!terminal.files) {
541
+ return terminal
542
+ }
543
+
544
+ return {
545
+ ...terminal,
546
+
547
+ files: pipe(
548
+ terminal.files,
549
+ mapValues(file => {
550
+ if (typeof file === "string") {
551
+ return { content: file }
552
+ }
553
+
554
+ return file
555
+ }),
556
+ pickBy(value => !!value?.content),
557
+ ),
558
+ }
559
+ })
560
+ }
561
+
562
+ function mapTriggers(triggers: Unwrap<ExtraOutputs["$triggers"]>): InstanceTrigger[] {
563
+ if (!triggers) {
564
+ return []
565
+ }
566
+
567
+ if (Array.isArray(triggers)) {
568
+ return triggers.filter(trigger => !!trigger)
569
+ }
570
+
571
+ return Object.entries(triggers)
572
+ .filter(([, trigger]) => !!trigger)
573
+ .map(([name, trigger]) => ({ ...(trigger as InstanceTrigger), name }))
574
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,184 @@
1
+ import { type Input, type Unwrap, type Output, output, all } from "@pulumi/pulumi"
2
+
3
+ /**
4
+ * The input type for an array of inputs.
5
+ * The same as `Input<Input<T>[]>`, but more readable.
6
+ */
7
+ export type InputArray<T> = Input<Input<T>[]>
8
+
9
+ /**
10
+ * The input type for a map of inputs.
11
+ * The same as `Input<Record<string, Input<T>>>`, but more readable.
12
+ */
13
+ export type InputMap<T> = Input<Readonly<Record<string, Input<T>>>>
14
+
15
+ /**
16
+ * The input or input array type for a value.
17
+ */
18
+ export type InputOrArray<T> = Input<T> | InputArray<T>
19
+
20
+ /**
21
+ * The input of inputs of inputs of inputs, so you got the idea.
22
+ */
23
+ export type DeepInput<T> = [T] extends [Record<string, unknown> | undefined]
24
+ ? [T] extends [infer U | undefined]
25
+ ? Input<{ [K in keyof U]: DeepInput<U[K]> } | undefined>
26
+ : Input<{ [K in keyof T]: DeepInput<T[K]> }>
27
+ : [T] extends [Array<unknown> | undefined]
28
+ ? [T] extends [(infer U)[] | undefined]
29
+ ? Input<DeepInput<U>[] | undefined>
30
+ : Input<DeepInput<T>[]>
31
+ : Input<T>
32
+
33
+ /**
34
+ * Merges the given array of `InputOrArray` values into a single flat output array.
35
+ *
36
+ * @param values The values to merge.
37
+ * @returns The merged output array.
38
+ */
39
+ export function flattenInputs<T>(...values: (InputOrArray<T> | undefined)[]): Output<T[]> {
40
+ return all(values).apply(allValues => {
41
+ const result: T[] = []
42
+ for (const value of allValues) {
43
+ if (Array.isArray(value)) {
44
+ result.push(...(value as T[]))
45
+ } else if (value) {
46
+ result.push(value as T)
47
+ }
48
+ }
49
+ return result
50
+ })
51
+ }
52
+
53
+ /**
54
+ * Maps each element of an input array to a new value.
55
+ * Produces an output array with the same length.
56
+ *
57
+ * @param array The input array.
58
+ * @param fn The mapping function.
59
+ * @returns The output array.
60
+ */
61
+ export function mapInputs<T, U>(
62
+ array: InputArray<T>,
63
+ fn: (v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U,
64
+ ): Output<U[]> {
65
+ return output(array).apply(array => {
66
+ return array?.map((v, index) => fn(v as Unwrap<T>, index, array as Unwrap<T>[])) ?? []
67
+ })
68
+ }
69
+
70
+ export function flatMapInput<T, U>(
71
+ v1: InputOrArray<T>,
72
+ v2: InputOrArray<T>,
73
+ fn: (v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U,
74
+ ): Output<U[]>
75
+
76
+ export function flatMapInput<T, U>(
77
+ v1: InputOrArray<T>,
78
+ v2: InputOrArray<T>,
79
+ v3: InputOrArray<T>,
80
+ fn: (v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U,
81
+ ): Output<U[]>
82
+
83
+ /**
84
+ * Merges the given array of `InputOrArray` values into a single flat output array and maps each element to a new value.
85
+ *
86
+ * @param values The values to merge.
87
+ * @param fn The mapping function.
88
+ */
89
+ export function flatMapInput<T, U>(
90
+ ...args: (InputOrArray<T> | ((v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U))[]
91
+ ): Output<U[]> {
92
+ const fn = args.pop() as (v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U
93
+ const values = args as InputOrArray<T>[]
94
+
95
+ return mapInputs(flattenInputs(...values), fn)
96
+ }
97
+
98
+ /**
99
+ * Map an optional value to another optional value.
100
+ *
101
+ * @param input The input value.
102
+ * @param func The function to apply to the input value.
103
+ * @returns The output value, or `undefined` if the input value is `undefined`.
104
+ */
105
+ export function mapOptional<T, U>(input: T | undefined, func: (value: T) => U): U | undefined {
106
+ if (input === undefined) {
107
+ return undefined
108
+ }
109
+
110
+ return func(input)
111
+ }
112
+
113
+ export function toPromise<T>(input: Input<T>): Promise<Unwrap<T>> {
114
+ return new Promise(resolve => output(input).apply(resolve))
115
+ }
116
+
117
+ export function singleton<T>(factory: () => T): () => T {
118
+ let instance: T | undefined
119
+ return () => {
120
+ if (instance === undefined) {
121
+ instance = factory()
122
+ }
123
+
124
+ return instance
125
+ }
126
+ }
127
+
128
+ export function providerFactory<TInput>(
129
+ factory: (name: string) => TInput,
130
+ ): (name: string) => TInput {
131
+ const instances = new Map<string, TInput>()
132
+ return name => {
133
+ if (!instances.has(name)) {
134
+ instances.set(name, factory(name))
135
+ }
136
+
137
+ return instances.get(name)!
138
+ }
139
+ }
140
+
141
+ export function mergeInputObjects<
142
+ T1 extends Record<string, unknown>,
143
+ T2 extends Record<string, unknown>,
144
+ >(obj1: Input<T1 | undefined> | undefined, obj2: Input<T2 | undefined> | undefined): Output<T1 & T2>
145
+
146
+ export function mergeInputObjects<
147
+ T1 extends Record<string, unknown>,
148
+ T2 extends Record<string, unknown>,
149
+ T3 extends Record<string, unknown>,
150
+ >(
151
+ obj1: Input<T1 | undefined> | undefined,
152
+ obj2: Input<T2 | undefined> | undefined,
153
+ obj3: Input<T3 | undefined> | undefined,
154
+ ): Output<T1 & T2 & T3>
155
+
156
+ /**
157
+ * Merges the given input objects into a single output object.
158
+ *
159
+ * @param objects The input objects.
160
+ * @returns The output object.
161
+ */
162
+ export function mergeInputObjects(
163
+ ...objects: Input<Record<string, unknown>>[]
164
+ ): Output<Record<string, unknown>> {
165
+ return output(objects).apply(array => {
166
+ return Object.assign({}, ...array) as Record<string, unknown>
167
+ })
168
+ }
169
+
170
+ export function normalize<T>(item: T | undefined, collection: T[] | undefined): T[] {
171
+ if (item && collection) {
172
+ return [item, ...collection]
173
+ }
174
+
175
+ if (item) {
176
+ return [item]
177
+ }
178
+
179
+ return collection ?? []
180
+ }
181
+
182
+ export function apply<T, U>(fn: (value: Unwrap<T>) => U): (input: Input<T>) => Output<U> {
183
+ return input => output(input).apply(fn)
184
+ }
package/dist/index.d.ts DELETED
@@ -1,153 +0,0 @@
1
- import { Input, Output, Unwrap } from '@pulumi/pulumi';
2
- export * from '@pulumi/pulumi';
3
- import { ArgumentValue, ComponentInputSpec, Unit, Entity } from '@highstate/contract';
4
- import { Static } from '@sinclair/typebox';
5
-
6
- /**
7
- * The input type for an array of inputs.
8
- * The same as `Input<Input<T>[]>`, but more readable.
9
- */
10
- type InputArray<T> = Input<Input<T>[]>;
11
- /**
12
- * The input type for a map of inputs.
13
- * The same as `Input<Record<string, Input<T>>>`, but more readable.
14
- */
15
- type InputMap<T> = Input<Readonly<Record<string, Input<T>>>>;
16
- /**
17
- * The input or input array type for a value.
18
- */
19
- type InputOrArray<T> = Input<T> | InputArray<T>;
20
- /**
21
- * The input of inputs of inputs of inputs, so you got the idea.
22
- */
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<{
26
- [K in keyof T]: DeepInput<T[K]>;
27
- }> : [T] extends [Array<unknown> | undefined] ? [T] extends [(infer U)[] | undefined] ? Input<DeepInput<U>[] | undefined> : Input<DeepInput<T>[]> : Input<T>;
28
- /**
29
- * Merges the given array of `InputOrArray` values into a single flat output array.
30
- *
31
- * @param values The values to merge.
32
- * @returns The merged output array.
33
- */
34
- declare function flattenInputs<T>(...values: (InputOrArray<T> | undefined)[]): Output<T[]>;
35
- /**
36
- * Maps each element of an input array to a new value.
37
- * Produces an output array with the same length.
38
- *
39
- * @param array The input array.
40
- * @param fn The mapping function.
41
- * @returns The output array.
42
- */
43
- declare function mapInputs<T, U>(array: InputArray<T>, fn: (v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U): Output<U[]>;
44
- declare function flatMapInput<T, U>(v1: InputOrArray<T>, v2: InputOrArray<T>, fn: (v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U): Output<U[]>;
45
- declare function flatMapInput<T, U>(v1: InputOrArray<T>, v2: InputOrArray<T>, v3: InputOrArray<T>, fn: (v: Unwrap<T>, index: number, all: Unwrap<T>[]) => U): Output<U[]>;
46
- /**
47
- * Map an optional value to another optional value.
48
- *
49
- * @param input The input value.
50
- * @param func The function to apply to the input value.
51
- * @returns The output value, or `undefined` if the input value is `undefined`.
52
- */
53
- declare function mapOptional<T, U>(input: T | undefined, func: (value: T) => U): U | undefined;
54
- declare function toPromise<T>(input: Input<T>): Promise<Unwrap<T>>;
55
- declare function singleton<T>(factory: () => T): () => T;
56
- declare function providerFactory<TInput>(factory: (name: string) => TInput): (name: string) => TInput;
57
- declare function mergeInputObjects<T1 extends Record<string, unknown>, T2 extends Record<string, unknown>>(obj1: Input<T1 | undefined> | undefined, obj2: Input<T2 | undefined> | undefined): Output<T1 & T2>;
58
- declare function mergeInputObjects<T1 extends Record<string, unknown>, T2 extends Record<string, unknown>, T3 extends Record<string, unknown>>(obj1: Input<T1 | undefined> | undefined, obj2: Input<T2 | undefined> | undefined, obj3: Input<T3 | undefined> | undefined): Output<T1 & T2 & T3>;
59
- declare function normalize<T>(item: T | undefined, collection: T[] | undefined): T[];
60
- declare function apply<T, U>(fn: (value: Unwrap<T>) => U): (input: Input<T>) => Output<U>;
61
-
62
- type InstanceTerminalFile = {
63
- content: Input<string | undefined>;
64
- mode?: Input<number | undefined>;
65
- isBinary?: Input<boolean>;
66
- };
67
- type InstanceTerminal = {
68
- name: Input<string>;
69
- title: Input<string>;
70
- description?: Input<string>;
71
- image: Input<string>;
72
- command: InputArray<string>;
73
- cwd?: Input<string | undefined>;
74
- env?: InputMap<string | undefined>;
75
- files?: InputMap<InstanceTerminalFile | string | undefined>;
76
- };
77
- type StatusField = {
78
- name: Input<string>;
79
- value?: Input<string | undefined>;
80
- displayName?: Input<string | undefined>;
81
- sensitive?: Input<boolean | undefined>;
82
- url?: Input<string | undefined>;
83
- };
84
- type InstanceFile = {
85
- name: Input<string>;
86
- contentType: Input<string>;
87
- content: Input<string>;
88
- };
89
- type InstancePageBlock = {
90
- type: "markdown";
91
- content: Input<string>;
92
- } | {
93
- type: "qr";
94
- content: Input<string>;
95
- showContent?: boolean;
96
- language?: string;
97
- } | {
98
- type: "file";
99
- fileMeta: Omit<InstanceFile, "content">;
100
- };
101
- type InstancePage = {
102
- name: Input<string>;
103
- title: Input<string>;
104
- content: InputArray<InstancePageBlock>;
105
- };
106
- type InstanceTriggerSpec = {
107
- type: "before-destroy";
108
- } | {
109
- type: "schedule";
110
- schedule: string;
111
- };
112
- type InstanceTrigger = {
113
- name: Input<string>;
114
- title: Input<string>;
115
- description?: Input<string>;
116
- spec: Input<InstanceTriggerSpec>;
117
- };
118
- type ExtraOutputs = {
119
- $status?: InputMap<Omit<StatusField, "name"> | string | undefined> | InputArray<StatusField | undefined>;
120
- $terminals?: InputMap<Omit<InstanceTerminal, "name"> | undefined> | InputArray<InstanceTerminal | undefined>;
121
- $pages?: InputMap<Omit<InstancePage, "name"> | undefined> | InputArray<InstancePage | undefined>;
122
- $files?: InputMap<Omit<InstanceFile, "name"> | undefined> | InputArray<InstanceFile | undefined>;
123
- $triggers?: InputMap<Omit<InstanceTrigger, "name"> | undefined> | InputArray<InstanceTrigger | undefined>;
124
- };
125
- type InstanceTriggerInvocation = {
126
- name: string;
127
- };
128
- type OutputMapToDeepInputMap<T extends Record<string, unknown>> = T extends Record<string, never> ? ExtraOutputs : {
129
- [K in keyof T]: DeepInput<T[K]>;
130
- } & ExtraOutputs;
131
- interface UnitContext<TArgs extends Record<string, ArgumentValue>, TInputs extends Record<string, unknown>, TOutputs extends Record<string, unknown>, TSecrets extends Record<string, ArgumentValue>> {
132
- args: TArgs;
133
- instanceId: string;
134
- type: string;
135
- name: string;
136
- secrets: Output<TSecrets>;
137
- inputs: {
138
- [K in keyof TInputs]: undefined extends TInputs[K] ? Output<NonNullable<TInputs[K]>> | undefined : Output<TInputs[K]>;
139
- };
140
- invokedTriggers: InstanceTriggerInvocation[];
141
- outputs(this: void, outputs?: OutputMapToDeepInputMap<TOutputs>): Promise<unknown>;
142
- }
143
- 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;
144
- type InputSpecMapToValueMap<T extends Record<string, ComponentInputSpec>> = T extends Record<string, never> ? Record<string, never> : {
145
- [K in keyof T]: InputSpecToValue<T[K]>;
146
- };
147
- 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>;
148
- type EntityValue<T extends Entity> = Static<T["schema"]>;
149
- type EntityInput<T extends Entity> = Output<EntityValue<T>>;
150
-
151
- declare function getOrCreateSecret<TSecrets extends Record<string, unknown>, TResult extends TSecrets[keyof TSecrets]>(secrets: Output<TSecrets>, key: keyof TSecrets, create: () => Input<TResult>): Output<TResult>;
152
-
153
- export { type DeepInput, type EntityInput, type EntityValue, type ExtraOutputs, type InputArray, type InputMap, type InputOrArray, type InstanceFile, type InstancePage, type InstancePageBlock, type InstanceTerminal, type InstanceTerminalFile, type InstanceTrigger, type InstanceTriggerInvocation, type InstanceTriggerSpec, type StatusField, type UnitContext, apply, flatMapInput, flattenInputs, forUnit, getOrCreateSecret, mapInputs, mapOptional, mergeInputObjects, normalize, providerFactory, singleton, toPromise };