@highstate/contract 0.19.1 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/instance.ts CHANGED
@@ -1,7 +1,10 @@
1
- import type { Entity, EntityTypes } from "./entity"
2
- import type { boundaryInput, boundaryInputs } from "./evaluation"
1
+ /** biome-ignore-all lint/suspicious/noExplicitAny: for simplicity of the API, maybe fix later */
2
+
3
+ import type { Entity, EntityIncludeRef, EntityTypes } from "./entity"
3
4
  import { z } from "zod"
4
5
  import { componentKindSchema } from "./component"
6
+ import { boundaryInput } from "./evaluation"
7
+ import { createInput, createNonProvidedInput } from "./instance-input"
5
8
  import {
6
9
  type GenericName,
7
10
  genericNameSchema,
@@ -12,31 +15,235 @@ import {
12
15
 
13
16
  declare const type: unique symbol
14
17
 
15
- export type InstanceInput<TTypes extends EntityTypes = EntityTypes> = {
18
+ export type InstanceInput = z.infer<typeof instanceInputSchema>
19
+
20
+ export type RuntimeInput<
21
+ TTypes extends EntityTypes = EntityTypes,
22
+ TPath extends string | undefined = string | undefined,
23
+ > = {
16
24
  [type]?: TTypes
17
- [boundaryInput]?: InstanceInput
18
- instanceId: InstanceId
19
- output: string
25
+ [boundaryInput]: InstanceInput
26
+ } & (
27
+ | ({
28
+ provided: true
29
+ instanceId: InstanceId
30
+ output: string
31
+ } & (undefined extends TPath ? { path?: string } : { path: TPath }))
32
+ | {
33
+ provided: false
34
+ path?: string
35
+ }
36
+ )
37
+
38
+ export type MultipleInput<
39
+ TInput extends RuntimeInput = RuntimeInput,
40
+ TSelectors extends Record<string, unknown> = Record<never, never>,
41
+ > = TInput[] &
42
+ TSelectors & {
43
+ [boundaryInput]: InstanceInput
44
+ path?: string
45
+ }
46
+
47
+ type RequiredInputChildValue<TValue> = TValue extends RuntimeInput
48
+ ? RequiredInput<TValue>
49
+ : TValue extends MultipleInput<infer TItem, infer TSelectors>
50
+ ? MultipleInput<RequiredInput<TItem>, RequiredInputChildSelectors<TSelectors>>
51
+ : TValue extends Array<infer TItem>
52
+ ? Array<RequiredInputChildValue<TItem>>
53
+ : TValue
54
+
55
+ type RequiredInputChildSelectors<TSelectors extends Record<string, unknown>> = {
56
+ [K in keyof TSelectors]: RequiredInputChildValue<TSelectors[K]>
57
+ }
58
+
59
+ type RequiredInputChildren<TInput extends RuntimeInput> = {
60
+ [K in keyof TInput as K extends
61
+ | "instanceId"
62
+ | "output"
63
+ | "path"
64
+ | "provided"
65
+ | typeof boundaryInput
66
+ | typeof type
67
+ ? never
68
+ : K]: RequiredInputChildValue<TInput[K]>
20
69
  }
21
70
 
71
+ type RequiredInputProvidedBranch<TInput extends RuntimeInput> = Extract<TInput, { provided: true }>
72
+
73
+ type StrictRequiredInput<TInput extends RuntimeInput> = RequiredInputProvidedBranch<TInput> &
74
+ RequiredInputChildren<RequiredInputProvidedBranch<TInput>>
75
+
76
+ export type RequiredInput<TInput extends RuntimeInput = RuntimeInput> = StrictRequiredInput<TInput>
77
+
78
+ type RequiredMultipleInputSelectors<TInput extends RuntimeInput> = LiftMultipleSelectorFields<
79
+ RequiredInputChildren<RequiredInputProvidedBranch<TInput>>
80
+ >
81
+
82
+ export type RequiredMultipleInput<TInput extends RuntimeInput = RuntimeInput> = MultipleInput<
83
+ RequiredInput<TInput>,
84
+ RequiredMultipleInputSelectors<TInput>
85
+ >
86
+
87
+ export type RequiredMultipleInputs<TInput extends RuntimeInput = RuntimeInput> =
88
+ RequiredMultipleInput<TInput>
89
+
22
90
  export type EntityInput<TEntity extends Entity> = TEntity extends Entity<
23
91
  VersionedName,
24
- infer TImplementedTypes
92
+ infer TImplementedTypes,
93
+ z.ZodTypeAny,
94
+ unknown,
95
+ unknown,
96
+ infer TIncludes
25
97
  >
26
- ? InstanceInput<TImplementedTypes>
98
+ ? RuntimeInput<TImplementedTypes, undefined> &
99
+ (TIncludes extends Record<string, EntityIncludeRef>
100
+ ? EntityInputIncludes<TIncludes>
101
+ : Record<never, never>)
27
102
  : never
28
103
 
29
- export type OptionalInstanceInput<TTypes extends EntityTypes = EntityTypes> =
30
- | ({ provided: true } & InstanceInput<TTypes>)
31
- | { provided: false; [boundaryInput]?: InstanceInput }
104
+ export type RequiredEntityInput<TEntity extends Entity> = RequiredInput<EntityInput<TEntity>>
105
+
106
+ type EntityInputDepth = [1, 1, 1, 1]
107
+
108
+ type DecDepth<T extends readonly unknown[]> = T extends readonly [unknown, ...infer Rest]
109
+ ? Rest
110
+ : readonly []
111
+
112
+ type ResolveIncludeEntity<TIncludeRef> = TIncludeRef extends { entity: infer E }
113
+ ? E extends () => infer ER
114
+ ? ER
115
+ : E
116
+ : TIncludeRef
117
+
118
+ type IncludeMultiple<TIncludeRef> = TIncludeRef extends { multiple?: infer M }
119
+ ? M extends true
120
+ ? true
121
+ : false
122
+ : false
123
+
124
+ type IncludeRequired<TIncludeRef> = TIncludeRef extends { required?: infer R }
125
+ ? R extends false
126
+ ? false
127
+ : true
128
+ : true
129
+
130
+ type IncludeRefValue<
131
+ TIncludeRef,
132
+ TDepth extends readonly unknown[],
133
+ > = ResolveIncludeEntity<TIncludeRef> extends infer TEntity
134
+ ? TEntity extends Entity
135
+ ? IncludeMultiple<TIncludeRef> extends true
136
+ ? MultipleInput<
137
+ EntityInputWithDepth<TEntity, TDepth>,
138
+ TDepth extends readonly []
139
+ ? Record<never, never>
140
+ : TEntity extends Entity<
141
+ VersionedName,
142
+ EntityTypes,
143
+ z.ZodTypeAny,
144
+ unknown,
145
+ unknown,
146
+ infer TIncludes
147
+ >
148
+ ? TIncludes extends Record<string, EntityIncludeRef>
149
+ ? LiftMultipleSelectorFields<EntityInputIncludes<TIncludes, DecDepth<TDepth>>>
150
+ : Record<never, never>
151
+ : Record<never, never>
152
+ >
153
+ : IncludeRequired<TIncludeRef> extends false
154
+ ? OptionalEntityInput<TEntity, TDepth>
155
+ : EntityInputWithDepth<TEntity, TDepth>
156
+ : never
157
+ : never
32
158
 
33
- export type InstanceInputGroup<TTypes extends EntityTypes = EntityTypes> =
34
- InstanceInput<TTypes>[] & {
35
- [boundaryInputs]?: InstanceInputGroup<TTypes>
36
- }
159
+ type OptionalEntityInput<TEntity extends Entity, TDepth extends readonly unknown[]> =
160
+ | ({ provided: true } & EntityInputWithDepth<TEntity, TDepth>)
161
+ | ({ provided: false; [boundaryInput]: InstanceInput } & OptionalizedInputFields<
162
+ EntityInputWithDepth<TEntity, TDepth>
163
+ >)
164
+
165
+ type OptionalizeInputValue<T> = [T] extends [InstanceInput]
166
+ ? RuntimeInput
167
+ : T extends MultipleInput<infer TItem, infer TSelectors>
168
+ ? MultipleInput<OptionalizeInputValue<TItem>, OptionalizedSelectorFields<TSelectors>>
169
+ : T extends Array<infer TItem>
170
+ ? Array<OptionalizeInputValue<TItem>>
171
+ : T
172
+
173
+ type OptionalizedSelectorFields<TSelectors extends Record<string, unknown>> = {
174
+ [K in keyof TSelectors]: OptionalizeInputValue<TSelectors[K]>
175
+ }
176
+
177
+ type RuntimeInputSelectorFields<TInput extends RuntimeInput> = {
178
+ [K in keyof TInput as K extends
179
+ | "instanceId"
180
+ | "output"
181
+ | "path"
182
+ | "provided"
183
+ | typeof boundaryInput
184
+ | typeof type
185
+ ? never
186
+ : K]: LiftMultipleSelectorValue<TInput[K]>
187
+ }
188
+
189
+ type LiftMultipleSelectorValue<T> = T extends MultipleInput<infer TItem, infer TSelectors>
190
+ ? MultipleInput<TItem, LiftMultipleSelectorFields<TSelectors>>
191
+ : T extends RuntimeInput
192
+ ? MultipleInput<T, RuntimeInputSelectorFields<T>>
193
+ : T
194
+
195
+ type LiftMultipleSelectorFields<TSelectors extends Record<string, unknown>> = {
196
+ [K in keyof TSelectors]: LiftMultipleSelectorValue<TSelectors[K]>
197
+ }
198
+
199
+ type OptionalizedInputFields<TInput extends RuntimeInput> = {
200
+ [K in keyof TInput as K extends "instanceId" | "output" | "provided" | typeof boundaryInput
201
+ ? never
202
+ : K]: OptionalizeInputValue<TInput[K]>
203
+ }
204
+
205
+ type EntityInputWithDepth<
206
+ TEntity extends Entity,
207
+ TDepth extends readonly unknown[],
208
+ > = TEntity extends Entity<
209
+ VersionedName,
210
+ infer TImplementedTypes,
211
+ z.ZodTypeAny,
212
+ unknown,
213
+ unknown,
214
+ infer TIncludes
215
+ >
216
+ ? RuntimeInput<TImplementedTypes, undefined> &
217
+ (TDepth extends readonly []
218
+ ? Record<never, never>
219
+ : TIncludes extends Record<string, EntityIncludeRef>
220
+ ? EntityInputIncludes<TIncludes, DecDepth<TDepth>>
221
+ : Record<never, never>)
222
+ : never
223
+
224
+ type EntityInputIncludes<
225
+ TIncludes extends Record<string, EntityIncludeRef>,
226
+ TDepth extends readonly unknown[] = EntityInputDepth,
227
+ > = TIncludes extends Record<string, never>
228
+ ? Record<never, never>
229
+ : string extends keyof TIncludes
230
+ ? Record<never, never>
231
+ : {
232
+ [K in keyof TIncludes]: IncludeRefValue<TIncludes[K], TDepth>
233
+ }
234
+
235
+ export type InstanceInputGroup<TTypes extends EntityTypes = EntityTypes> = MultipleInput<
236
+ RuntimeInput<TTypes>
237
+ >
238
+
239
+ type SelectInputResult<TInput extends RuntimeInput> = TInput extends RequiredInput<infer TRuntime>
240
+ ? TRuntime
241
+ : TInput
37
242
 
38
243
  export function inputKey(input: InstanceInput): string {
39
- return `${input.instanceId}:${input.output}`
244
+ return input.path
245
+ ? `${input.instanceId}:${input.output}:${input.path}`
246
+ : `${input.instanceId}:${input.output}`
40
247
  }
41
248
 
42
249
  export const positionSchema = z.object({
@@ -53,6 +260,7 @@ export type InstanceId = z.infer<typeof instanceIdSchema>
53
260
  export const instanceInputSchema = z.object({
54
261
  instanceId: instanceIdSchema,
55
262
  output: z.string(),
263
+ path: z.string().optional(),
56
264
  })
57
265
 
58
266
  export const hubInputSchema = z.object({
@@ -209,52 +417,52 @@ export function parseInstanceId(
209
417
  return parts as [VersionedName, GenericName]
210
418
  }
211
419
 
212
- export function findInput<T extends EntityTypes>(
213
- inputs: InstanceInput<T>[],
420
+ /**
421
+ * Selects a single input from a group by instance id or instance name.
422
+ *
423
+ * The function accepts a plain array but still preserves Highstate boundary semantics.
424
+ * It first tries to read boundary metadata from the array object itself and then falls back
425
+ * to the first item boundary when needed.
426
+ *
427
+ * @param inputs The input group to search in.
428
+ * @param name The instance id or instance name to select.
429
+ * @returns The selected input with inherited group boundary, or a provided-false input when missing.
430
+ */
431
+ export function selectInput<TInput extends RuntimeInput>(
432
+ inputs: TInput[] & Partial<{ [boundaryInput]: InstanceInput }>,
214
433
  name: string,
215
- ): InstanceInput<T> | null {
216
- const matchedInputs = inputs.filter(
217
- input => parseInstanceId(input.instanceId)[1] === name || input.instanceId === name,
218
- )
434
+ ): SelectInputResult<TInput> {
435
+ const groupBoundary = inputs[boundaryInput] ?? inputs[0]?.[boundaryInput]
219
436
 
220
- if (matchedInputs.length === 0) {
221
- return null
222
- }
223
-
224
- if (matchedInputs.length > 1) {
437
+ if (inputs.length === 0 && !groupBoundary) {
225
438
  throw new Error(
226
- `Multiple inputs found for "${name}": ${matchedInputs.map(input => input.instanceId).join(", ")}. Specify the full instance id to disambiguate.`,
439
+ `Cannot select input "${name}": empty input group has no boundary metadata to build a missing input reference.`,
227
440
  )
228
441
  }
229
442
 
230
- return matchedInputs[0]
231
- }
232
-
233
- export function findRequiredInput<T extends EntityTypes>(
234
- inputs: InstanceInput<T>[],
235
- name: string,
236
- ): InstanceInput<T> {
237
- const input = findInput(inputs, name)
443
+ const input = inputs.find(
444
+ input =>
445
+ input.provided &&
446
+ (input.instanceId === name || parseInstanceId(input.instanceId)[1] === name),
447
+ )
238
448
 
239
- if (input === null) {
240
- throw new Error(`Required input "${name}" not found.`)
241
- }
449
+ if (!input || !input.provided) {
450
+ const fallbackBoundary =
451
+ groupBoundary ??
452
+ inputs.find(input => Boolean(input[boundaryInput]))?.[boundaryInput] ??
453
+ inputs[0]?.[boundaryInput]
242
454
 
243
- return input
244
- }
455
+ if (!fallbackBoundary) {
456
+ throw new Error(
457
+ `Cannot select input "${name}": input group has no boundary metadata to build a missing input reference.`,
458
+ )
459
+ }
245
460
 
246
- export function findInputs<T extends EntityTypes>(
247
- inputs: InstanceInput<T>[],
248
- names: string[],
249
- ): InstanceInput<T>[] {
250
- return names.map(name => findInput(inputs, name)).filter(Boolean) as InstanceInput<T>[]
251
- }
461
+ return createNonProvidedInput(fallbackBoundary) as SelectInputResult<TInput>
462
+ }
252
463
 
253
- export function findRequiredInputs<T extends EntityTypes>(
254
- inputs: InstanceInput<T>[],
255
- names: string[],
256
- ): InstanceInput<T>[] {
257
- return names.map(name => findRequiredInput(inputs, name))
464
+ const boundary = groupBoundary ?? input[boundaryInput]
465
+ return createInput(input, { boundary }) as SelectInputResult<TInput>
258
466
  }
259
467
 
260
468
  /**
@@ -265,8 +473,7 @@ export function findRequiredInputs<T extends EntityTypes>(
265
473
  export enum HighstateSignature {
266
474
  Artifact = "d55c63ac-3174-4756-808f-f778e99af0d1",
267
475
  Yaml = "c857cac5-caa6-4421-b82c-e561fbce6367",
268
- Id = "348d020e-0d9e-4ae7-9415-b91af99f5339",
269
- Ref = "6d7f9da0-9cb6-496d-b72e-cf85ee4d9cf8",
476
+ Secret = "240e5789-6ae4-4b22-b9d8-87169e8b4bab",
270
477
  }
271
478
 
272
479
  export const yamlValueSchema = z.object({
@@ -274,17 +481,6 @@ export const yamlValueSchema = z.object({
274
481
  value: z.string(),
275
482
  })
276
483
 
277
- export const objectWithIdSchema = z.object({
278
- [HighstateSignature.Id]: z.literal(true),
279
- id: z.number(),
280
- value: z.unknown(),
281
- })
282
-
283
- export const objectRefSchema = z.object({
284
- [HighstateSignature.Ref]: z.literal(true),
285
- id: z.number(),
286
- })
287
-
288
484
  export type YamlValue = z.infer<typeof yamlValueSchema>
289
485
 
290
486
  export const fileMetaSchema = z.object({
@@ -351,3 +547,49 @@ export const instanceStatusFieldSchema = z.object({
351
547
 
352
548
  export type InstanceStatusFieldValue = z.infer<typeof instanceStatusFieldValueSchema>
353
549
  export type InstanceStatusField = z.infer<typeof instanceStatusFieldSchema>
550
+
551
+ export function secretSchema<TSchema extends z.ZodType>(
552
+ schema: TSchema,
553
+ ): z.ZodCodec<
554
+ z.ZodUnion<
555
+ [
556
+ z.ZodObject<{
557
+ [HighstateSignature.Secret]: z.ZodLiteral<true>
558
+ value: TSchema
559
+ }>,
560
+ TSchema,
561
+ ]
562
+ >,
563
+ z.ZodObject<{
564
+ [HighstateSignature.Secret]: z.ZodLiteral<true>
565
+ value: TSchema
566
+ }>
567
+ > {
568
+ const secretType = z.object({
569
+ [HighstateSignature.Secret]: z.literal(true),
570
+ value: schema,
571
+ })
572
+
573
+ return z.codec(z.union([secretType, schema]), secretType, {
574
+ decode: value =>
575
+ typeof value === "object" && value !== null && HighstateSignature.Secret in value
576
+ ? (value as any)
577
+ : { [HighstateSignature.Secret]: true, value },
578
+ encode: value => value as any,
579
+ })
580
+ }
581
+
582
+ export type Secret<T> = {
583
+ [HighstateSignature.Secret]: true
584
+ value: T
585
+ }
586
+
587
+ /**
588
+ * Checks if the given value is a Secret.
589
+ *
590
+ * @param value The value to check.
591
+ * @returns True if the value is a Secret, false otherwise.
592
+ */
593
+ export function isSecret<T>(value: unknown): value is Secret<T> {
594
+ return typeof value === "object" && value !== null && HighstateSignature.Secret in value
595
+ }
@@ -0,0 +1,115 @@
1
+ function isRecord(value: unknown): value is Record<string, unknown> {
2
+ return typeof value === "object" && value !== null && !Array.isArray(value)
3
+ }
4
+
5
+ /**
6
+ * Normalizes JSON schema produced by Zod exports.
7
+ *
8
+ * In particular, it merges intersections of object schemas represented as
9
+ * `allOf: [{ type: "object", ... }, { type: "object", ... }, ...]` into a single
10
+ * object schema so that validators treat `additionalProperties` consistently.
11
+ */
12
+ export function fixJsonSchema(schema: unknown): unknown {
13
+ if (!isRecord(schema)) {
14
+ return schema
15
+ }
16
+
17
+ const allOf = schema.allOf
18
+ if (Array.isArray(allOf) && allOf.length > 0) {
19
+ const objectSchemas: Record<string, unknown>[] = []
20
+ const otherSchemas: unknown[] = []
21
+
22
+ for (const item of allOf) {
23
+ if (isRecord(item) && item.type === "object") {
24
+ objectSchemas.push(item)
25
+ continue
26
+ }
27
+
28
+ otherSchemas.push(item)
29
+ }
30
+
31
+ if (objectSchemas.length > 1) {
32
+ const required = new Set<string>()
33
+ const properties: Record<string, unknown> = {}
34
+ let additionalProperties: unknown
35
+
36
+ for (const objectSchema of objectSchemas) {
37
+ const objectRequired = objectSchema.required
38
+ if (Array.isArray(objectRequired)) {
39
+ for (const key of objectRequired) {
40
+ if (typeof key === "string") {
41
+ required.add(key)
42
+ }
43
+ }
44
+ }
45
+
46
+ const objectProperties = objectSchema.properties
47
+ if (isRecord(objectProperties)) {
48
+ for (const [key, value] of Object.entries(objectProperties)) {
49
+ const existing = properties[key]
50
+ if (existing === undefined) {
51
+ properties[key] = value
52
+ continue
53
+ }
54
+
55
+ properties[key] = { allOf: [existing, value] }
56
+ }
57
+ }
58
+
59
+ if ("additionalProperties" in objectSchema) {
60
+ if (additionalProperties === undefined) {
61
+ additionalProperties = objectSchema.additionalProperties
62
+ } else if (additionalProperties !== objectSchema.additionalProperties) {
63
+ additionalProperties = false
64
+ }
65
+ }
66
+ }
67
+
68
+ const mergedObjectSchema: Record<string, unknown> = {
69
+ type: "object",
70
+ properties,
71
+ ...(required.size > 0 ? { required: Array.from(required) } : {}),
72
+ ...(additionalProperties !== undefined
73
+ ? { additionalProperties }
74
+ : { additionalProperties: false }),
75
+ }
76
+
77
+ const merged =
78
+ otherSchemas.length === 0
79
+ ? mergedObjectSchema
80
+ : {
81
+ ...schema,
82
+ allOf: [mergedObjectSchema, ...otherSchemas],
83
+ }
84
+
85
+ return fixJsonSchema(merged)
86
+ }
87
+ }
88
+
89
+ const next: Record<string, unknown> = { ...schema }
90
+
91
+ if (Array.isArray(next.allOf)) {
92
+ next.allOf = next.allOf.map(fixJsonSchema)
93
+ }
94
+ if (Array.isArray(next.anyOf)) {
95
+ next.anyOf = next.anyOf.map(fixJsonSchema)
96
+ }
97
+ if (Array.isArray(next.oneOf)) {
98
+ next.oneOf = next.oneOf.map(fixJsonSchema)
99
+ }
100
+ if (isRecord(next.properties)) {
101
+ next.properties = Object.fromEntries(
102
+ Object.entries(next.properties).map(([key, value]) => [key, fixJsonSchema(value)]),
103
+ )
104
+ }
105
+ if (isRecord(next.items)) {
106
+ next.items = fixJsonSchema(next.items)
107
+ } else if (Array.isArray(next.items)) {
108
+ next.items = next.items.map(fixJsonSchema)
109
+ }
110
+ if (isRecord(next.additionalProperties)) {
111
+ next.additionalProperties = fixJsonSchema(next.additionalProperties)
112
+ }
113
+
114
+ return next
115
+ }
package/src/pulumi.ts CHANGED
@@ -1,33 +1,49 @@
1
1
  import { parse } from "yaml"
2
2
  import { z } from "zod"
3
- import { entityInclusionSchema } from "./entity"
4
3
  import {
5
4
  fileMetaSchema,
6
5
  HighstateSignature,
7
- instanceIdSchema,
8
6
  instanceInputSchema,
7
+ secretSchema,
9
8
  yamlValueSchema,
10
9
  } from "./instance"
11
10
  import { commonObjectMetaSchema } from "./meta"
12
11
  import { triggerInvocationSchema } from "./trigger"
13
12
 
14
- export type UnitInputReference = z.infer<typeof unitInputReference>
15
-
16
- export const unitInputReference = z.object({
13
+ export const unitInputSourceSchema = z.object({
17
14
  ...instanceInputSchema.shape,
15
+ })
18
16
 
17
+ export type UnitInputSource = z.infer<typeof unitInputSourceSchema>
18
+
19
+ export const unitInputValueSchema = z.object({
19
20
  /**
20
- * The resolved inclusion needed to extract the input value.
21
+ * Inline resolved value passed to the unit.
22
+ *
23
+ * The backend is responsible for resolving the correct entity snapshot value
24
+ * and applying any inclusion transformations.
21
25
  */
22
- inclusion: entityInclusionSchema.optional(),
26
+ value: z.unknown(),
27
+
28
+ /**
29
+ * Optional provenance of the value.
30
+ */
31
+ source: unitInputSourceSchema.optional(),
23
32
  })
24
33
 
34
+ export type UnitInputValue = z.infer<typeof unitInputValueSchema>
35
+
25
36
  export const unitConfigSchema = z.object({
26
37
  /**
27
38
  * The ID of the instance.
28
39
  */
29
40
  instanceId: z.string(),
30
41
 
42
+ /**
43
+ * The state ID of the instance.
44
+ */
45
+ stateId: z.string(),
46
+
31
47
  /**
32
48
  * The record of argument values for the unit.
33
49
  */
@@ -36,7 +52,7 @@ export const unitConfigSchema = z.object({
36
52
  /**
37
53
  * The record of input references for the unit.
38
54
  */
39
- inputs: z.record(z.string(), unitInputReference.array()),
55
+ inputs: z.record(z.string(), unitInputValueSchema.array()),
40
56
 
41
57
  /**
42
58
  * The list of triggers that have been invoked for this unit.
@@ -44,14 +60,11 @@ export const unitConfigSchema = z.object({
44
60
  invokedTriggers: triggerInvocationSchema.array(),
45
61
 
46
62
  /**
47
- * The list of secret names that exists and provided to the unit.
63
+ * The record of secret values provided to the unit.
64
+ *
65
+ * It is stored in Pulumi stack config as a secret.
48
66
  */
49
- secretNames: z.string().array(),
50
-
51
- /**
52
- * The map of instance ID to state ID in order to resolve instance references.
53
- */
54
- stateIdMap: z.record(instanceIdSchema, z.string()),
67
+ secretValues: z.record(z.string(), z.unknown()),
55
68
 
56
69
  /**
57
70
  * The base path for imports.
@@ -87,7 +100,6 @@ export function parseArgumentValue(value: unknown): unknown {
87
100
 
88
101
  export enum HighstateConfigKey {
89
102
  Config = "highstate",
90
- Secrets = "highstate.secrets",
91
103
  }
92
104
 
93
105
  export const unitArtifactId = Symbol("unitArtifactId")
@@ -118,6 +130,23 @@ export const fileContentSchema = z.union([
118
130
  */
119
131
  value: z.string(),
120
132
  }),
133
+ z.object({
134
+ type: z.literal("embedded-secret"),
135
+
136
+ /**
137
+ * Whether the content is binary or not.
138
+ *
139
+ * If true, the `value` will be a base64 encoded string.
140
+ */
141
+ isBinary: z.boolean().optional(),
142
+
143
+ /**
144
+ * The content of the file wrapped as a Highstate secret.
145
+ *
146
+ * If `isBinary` is true, this will be a base64 encoded string.
147
+ */
148
+ value: secretSchema(z.string()),
149
+ }),
121
150
  z.object({
122
151
  type: z.literal("artifact"),
123
152
  ...unitArtifactSchema.shape,