@@ -77,6 +77,34 @@ type TypedJSON struct {
7777 ChainOverrides []uint64 `json:"chainOverrides"` // Optional field for chain overrides
7878}
7979
80+ func parseTypedInput (inputStr string ) (TypedJSON , error ) {
81+ if inputStr == "" {
82+ return TypedJSON {}, errors .New ("input is empty" )
83+ }
84+
85+ var inputObject TypedJSON
86+ if err := json .Unmarshal ([]byte (inputStr ), & inputObject ); err != nil {
87+ return TypedJSON {}, fmt .Errorf ("JSON must be in JSON format with 'payload' fields: %w" , err )
88+ }
89+ if len (inputObject .Payload ) == 0 {
90+ return TypedJSON {}, errors .New ("'payload' field is required" )
91+ }
92+
93+ return inputObject , nil
94+ }
95+
96+ func decodePayload [C any ](payload json.RawMessage ) (C , error ) {
97+ var config C
98+
99+ payloadDecoder := json .NewDecoder (strings .NewReader (string (payload )))
100+ payloadDecoder .DisallowUnknownFields ()
101+ if err := payloadDecoder .Decode (& config ); err != nil {
102+ return config , fmt .Errorf ("failed to unmarshal payload: %w" , err )
103+ }
104+
105+ return config , nil
106+ }
107+
80108// WithJSON returns a fully configured changeset, which pairs a [fdeployment.ChangeSet] with its configuration based
81109// a JSON input. It also allows extensions, such as a PostProcessing function.
82110// InputStr must be a JSON object with a "payload" field that contains the actual input data for a Durable Pipeline.
@@ -92,30 +120,13 @@ type TypedJSON struct {
92120// Note: Prefer WithEnvInput for durable_pipelines.go
93121func (f WrappedChangeSet [C ]) WithJSON (_ C , inputStr string ) ConfiguredChangeSet {
94122 return ChangeSetImpl [C ]{changeset : f , configProvider : func () (C , error ) {
95- var config C
96-
97- if inputStr == "" {
98- return config , errors .New ("input is empty" )
99- }
100-
101- var inputObject TypedJSON
102- if err := json .Unmarshal ([]byte (inputStr ), & inputObject ); err != nil {
103- return config , fmt .Errorf ("JSON must be in JSON format with 'payload' fields: %w" , err )
104- }
105-
106- // If payload is null, decode it as null (which will give zero value)
107- // If payload is missing, return an error
108- if len (inputObject .Payload ) == 0 {
109- return config , errors .New ("'payload' field is required" )
110- }
111-
112- payloadDecoder := json .NewDecoder (strings .NewReader (string (inputObject .Payload )))
113- payloadDecoder .DisallowUnknownFields ()
114- if err := payloadDecoder .Decode (& config ); err != nil {
115- return config , fmt .Errorf ("failed to unmarshal payload: %w" , err )
123+ inputObject , err := parseTypedInput (inputStr )
124+ if err != nil {
125+ var zero C
126+ return zero , err
116127 }
117128
118- return config , nil
129+ return decodePayload [ C ]( inputObject . Payload )
119130 },
120131 inputChainOverrides : func () ([]uint64 , error ) {
121132 return loadInputChainOverrides (inputStr )
@@ -151,41 +162,36 @@ func (f WrappedChangeSet[C]) WithEnvInput(opts ...EnvInputOption[C]) ConfiguredC
151162
152163 inputStr := os .Getenv ("DURABLE_PIPELINE_INPUT" )
153164
154- return ChangeSetImpl [C ]{changeset : f , configProvider : func () (C , error ) {
155- var config C
156-
157- if inputStr == "" {
158- return config , errors .New ("input is empty" )
159- }
160-
161- var inputObject TypedJSON
162- if err := json .Unmarshal ([]byte (inputStr ), & inputObject ); err != nil {
163- return config , fmt .Errorf ("JSON must be in JSON format with 'payload' fields: %w" , err )
164- }
165+ providerFromInput := func (rawInput string ) (C , error ) {
166+ var zero C
165167
166- // If payload is null, decode it as null (which will give zero value)
167- // If payload is missing, return an error
168- if len (inputObject .Payload ) == 0 {
169- return config , errors .New ("'payload' field is required" )
168+ inputObject , err := parseTypedInput (rawInput )
169+ if err != nil {
170+ return zero , err
170171 }
171172
172- payloadDecoder := json .NewDecoder (strings .NewReader (string (inputObject .Payload )))
173- payloadDecoder .DisallowUnknownFields ()
174- if err := payloadDecoder .Decode (& config ); err != nil {
175- return config , fmt .Errorf ("failed to unmarshal payload: %w" , err )
173+ config , err := decodePayload [C ](inputObject .Payload )
174+ if err != nil {
175+ return zero , err
176176 }
177177
178178 if options .inputModifier != nil {
179- conf , err := options .inputModifier (config )
180- if err != nil {
181- return conf , fmt .Errorf ("failed to apply input modifier: %w" , err )
179+ conf , modifierErr := options .inputModifier (config )
180+ if modifierErr != nil {
181+ return conf , fmt .Errorf ("failed to apply input modifier: %w" , modifierErr )
182182 }
183183
184184 return conf , nil
185185 }
186186
187187 return config , nil
188- },
188+ }
189+
190+ return ChangeSetImpl [C ]{changeset : f ,
191+ configProvider : func () (C , error ) {
192+ return providerFromInput (inputStr )
193+ },
194+ configProviderWithInput : providerFromInput ,
189195 inputChainOverrides : func () ([]uint64 , error ) {
190196 return loadInputChainOverrides (inputStr )
191197 },
@@ -221,21 +227,17 @@ func (f WrappedChangeSet[C]) WithConfigResolver(resolver fresolvers.ConfigResolv
221227 // Read input from environment variable
222228 inputStr := os .Getenv ("DURABLE_PIPELINE_INPUT" )
223229
224- configProvider := func () (C , error ) {
230+ configProviderFromInput := func (rawInput string ) (C , error ) {
225231 var zero C
226232
227- if inputStr == "" {
233+ if rawInput == "" {
228234 return zero , errors .New ("input is empty" )
229235 }
230236
231- // Parse JSON input
232237 var inputObject TypedJSON
233- if err := json .Unmarshal ([]byte (inputStr ), & inputObject ); err != nil {
238+ if err := json .Unmarshal ([]byte (rawInput ), & inputObject ); err != nil {
234239 return zero , fmt .Errorf ("failed to parse resolver input as JSON: %w" , err )
235240 }
236-
237- // If payload is null, pass it to the resolver (which will receive null)
238- // If payload field is missing, return an error
239241 if len (inputObject .Payload ) == 0 {
240242 return zero , errors .New ("'payload' field is required" )
241243 }
@@ -249,8 +251,12 @@ func (f WrappedChangeSet[C]) WithConfigResolver(resolver fresolvers.ConfigResolv
249251 return typedConfig , nil
250252 }
251253
252- return ChangeSetImpl [C ]{changeset : f , configProvider : configProvider ,
253- ConfigResolver : resolver ,
254+ return ChangeSetImpl [C ]{changeset : f ,
255+ configProvider : func () (C , error ) {
256+ return configProviderFromInput (inputStr )
257+ },
258+ configProviderWithInput : configProviderFromInput ,
259+ ConfigResolver : resolver ,
254260 inputChainOverrides : func () ([]uint64 , error ) {
255261 return loadInputChainOverrides (inputStr )
256262 },
@@ -260,9 +266,10 @@ func (f WrappedChangeSet[C]) WithConfigResolver(resolver fresolvers.ConfigResolv
260266var _ ConfiguredChangeSet = ChangeSetImpl [any ]{}
261267
262268type ChangeSetImpl [C any ] struct {
263- changeset WrappedChangeSet [C ]
264- configProvider func () (C , error )
265- inputChainOverrides func () ([]uint64 , error )
269+ changeset WrappedChangeSet [C ]
270+ configProvider func () (C , error )
271+ configProviderWithInput func (inputStr string ) (C , error )
272+ inputChainOverrides func () ([]uint64 , error )
266273
267274 // Present only when the changeset was wired with
268275 // Configure(...).WithConfigResolver(...)
@@ -287,6 +294,22 @@ func (ccs ChangeSetImpl[C]) Apply(env fdeployment.Environment) (fdeployment.Chan
287294 return ccs .changeset .operation .Apply (env , c )
288295}
289296
297+ func (ccs ChangeSetImpl [C ]) applyWithInput (env fdeployment.Environment , inputStr string ) (fdeployment.ChangesetOutput , error ) {
298+ if ccs .configProviderWithInput == nil {
299+ return ccs .Apply (env )
300+ }
301+
302+ c , err := ccs .configProviderWithInput (inputStr )
303+ if err != nil {
304+ return fdeployment.ChangesetOutput {}, err
305+ }
306+ if err := ccs .changeset .operation .VerifyPreconditions (env , c ); err != nil {
307+ return fdeployment.ChangesetOutput {}, err
308+ }
309+
310+ return ccs .changeset .operation .Apply (env , c )
311+ }
312+
290313func (ccs ChangeSetImpl [C ]) Configurations () (Configurations , error ) {
291314 var chainOverrides []uint64
292315 var err error
0 commit comments