@@ -20,6 +20,11 @@ import {getLogger} from '../../logging/logger.js';
2020 */
2121export type MrtEnvironment = components [ 'schemas' ] [ 'APITargetV2Create' ] ;
2222
23+ /**
24+ * Environment state from the MRT API.
25+ */
26+ export type MrtEnvironmentState = components [ 'schemas' ] [ 'StateEnum' ] ;
27+
2328type SsrRegion = components [ 'schemas' ] [ 'SsrRegionEnum' ] ;
2429type LogLevel = components [ 'schemas' ] [ 'LogLevelEnum' ] ;
2530
@@ -271,3 +276,173 @@ export async function deleteEnv(options: DeleteEnvOptions, auth: AuthStrategy):
271276
272277 logger . debug ( { slug} , '[MRT] Environment deleted successfully' ) ;
273278}
279+
280+ /**
281+ * Options for getting an MRT environment.
282+ */
283+ export interface GetEnvOptions {
284+ /**
285+ * The project slug containing the environment.
286+ */
287+ projectSlug : string ;
288+
289+ /**
290+ * Environment slug/identifier to retrieve.
291+ */
292+ slug : string ;
293+
294+ /**
295+ * MRT API origin URL.
296+ * @default "https://cloud.mobify.com"
297+ */
298+ origin ?: string ;
299+ }
300+
301+ /**
302+ * Gets an environment (target) from an MRT project.
303+ *
304+ * @param options - Environment retrieval options
305+ * @param auth - Authentication strategy (ApiKeyStrategy)
306+ * @returns The environment object from the API
307+ * @throws Error if retrieval fails
308+ *
309+ * @example
310+ * ```typescript
311+ * import { ApiKeyStrategy } from '@salesforce/b2c-tooling-sdk/auth';
312+ * import { getEnv } from '@salesforce/b2c-tooling-sdk/operations/mrt';
313+ *
314+ * const auth = new ApiKeyStrategy(process.env.MRT_API_KEY!, 'Authorization');
315+ *
316+ * const env = await getEnv({
317+ * projectSlug: 'my-storefront',
318+ * slug: 'staging'
319+ * }, auth);
320+ *
321+ * console.log(`Environment state: ${env.state}`);
322+ * ```
323+ */
324+ export async function getEnv ( options : GetEnvOptions , auth : AuthStrategy ) : Promise < MrtEnvironment > {
325+ const logger = getLogger ( ) ;
326+ const { projectSlug, slug, origin} = options ;
327+
328+ logger . debug ( { projectSlug, slug} , '[MRT] Getting environment' ) ;
329+
330+ const client = createMrtClient ( { origin : origin || DEFAULT_MRT_ORIGIN } , auth ) ;
331+
332+ const { data, error} = await client . GET ( '/api/projects/{project_slug}/target/{target_slug}/' , {
333+ params : {
334+ path : { project_slug : projectSlug , target_slug : slug } ,
335+ } ,
336+ } ) ;
337+
338+ if ( error ) {
339+ const errorMessage =
340+ typeof error === 'object' && error !== null && 'message' in error
341+ ? String ( ( error as { message : unknown } ) . message )
342+ : JSON . stringify ( error ) ;
343+ throw new Error ( `Failed to get environment: ${ errorMessage } ` ) ;
344+ }
345+
346+ logger . debug ( { slug : data . slug , state : data . state } , '[MRT] Environment retrieved' ) ;
347+
348+ return data ;
349+ }
350+
351+ /**
352+ * Terminal states for MRT environments (no longer changing).
353+ */
354+ const TERMINAL_STATES : MrtEnvironmentState [ ] = [ 'ACTIVE' , 'CREATE_FAILED' , 'PUBLISH_FAILED' ] ;
355+
356+ /**
357+ * Options for waiting for an MRT environment to be ready.
358+ */
359+ export interface WaitForEnvOptions extends GetEnvOptions {
360+ /**
361+ * Polling interval in milliseconds.
362+ * @default 10000
363+ */
364+ pollInterval ?: number ;
365+
366+ /**
367+ * Maximum time to wait in milliseconds.
368+ * @default 2700000 (45 minutes)
369+ */
370+ timeout ?: number ;
371+
372+ /**
373+ * Optional callback called on each poll with the current environment state.
374+ */
375+ onPoll ?: ( env : MrtEnvironment ) => void ;
376+ }
377+
378+ /**
379+ * Waits for an environment to reach a terminal state (ACTIVE or failed).
380+ *
381+ * Polls the environment status until it reaches ACTIVE, CREATE_FAILED,
382+ * or PUBLISH_FAILED state, or until the timeout is reached.
383+ *
384+ * @param options - Wait options including polling interval and timeout
385+ * @param auth - Authentication strategy (ApiKeyStrategy)
386+ * @returns The environment in its terminal state
387+ * @throws Error if timeout is reached or environment fails
388+ *
389+ * @example
390+ * ```typescript
391+ * import { ApiKeyStrategy } from '@salesforce/b2c-tooling-sdk/auth';
392+ * import { createEnv, waitForEnv } from '@salesforce/b2c-tooling-sdk/operations/mrt';
393+ *
394+ * const auth = new ApiKeyStrategy(process.env.MRT_API_KEY!, 'Authorization');
395+ *
396+ * // Create environment
397+ * const env = await createEnv({
398+ * projectSlug: 'my-storefront',
399+ * slug: 'staging',
400+ * name: 'Staging'
401+ * }, auth);
402+ *
403+ * // Wait for it to be ready
404+ * const readyEnv = await waitForEnv({
405+ * projectSlug: 'my-storefront',
406+ * slug: 'staging',
407+ * timeout: 60000, // 1 minute
408+ * onPoll: (e) => console.log(`State: ${e.state}`)
409+ * }, auth);
410+ *
411+ * if (readyEnv.state === 'ACTIVE') {
412+ * console.log('Environment is ready!');
413+ * }
414+ * ```
415+ */
416+ export async function waitForEnv ( options : WaitForEnvOptions , auth : AuthStrategy ) : Promise < MrtEnvironment > {
417+ const logger = getLogger ( ) ;
418+ const { projectSlug, slug, pollInterval = 10000 , timeout = 2700000 , onPoll, origin} = options ;
419+
420+ logger . debug ( { projectSlug, slug, pollInterval, timeout} , '[MRT] Waiting for environment' ) ;
421+
422+ const startTime = Date . now ( ) ;
423+
424+ while ( Date . now ( ) - startTime < timeout ) {
425+ const env = await getEnv ( { projectSlug, slug, origin} , auth ) ;
426+
427+ if ( onPoll ) {
428+ onPoll ( env ) ;
429+ }
430+
431+ if ( env . state && TERMINAL_STATES . includes ( env . state as MrtEnvironmentState ) ) {
432+ if ( env . state === 'CREATE_FAILED' ) {
433+ throw new Error ( `Environment creation failed` ) ;
434+ }
435+ if ( env . state === 'PUBLISH_FAILED' ) {
436+ throw new Error ( `Environment publish failed` ) ;
437+ }
438+ logger . debug ( { slug, state : env . state } , '[MRT] Environment reached terminal state' ) ;
439+ return env ;
440+ }
441+
442+ logger . debug ( { slug, state : env . state , elapsed : Date . now ( ) - startTime } , '[MRT] Environment still in progress' ) ;
443+
444+ await new Promise ( ( resolve ) => setTimeout ( resolve , pollInterval ) ) ;
445+ }
446+
447+ throw new Error ( `Timeout waiting for environment "${ slug } " to be ready after ${ timeout } ms` ) ;
448+ }
0 commit comments