diff --git a/packages/app/src/cli/models/app/loader.ts b/packages/app/src/cli/models/app/loader.ts index d83e575846c..8b249a1a960 100644 --- a/packages/app/src/cli/models/app/loader.ts +++ b/packages/app/src/cli/models/app/loader.ts @@ -90,6 +90,7 @@ export async function loadConfigurationFileContent( try { const configurationContent = await readFile(filepath) + // console.log('Initial undecoded config from TOML file', {configurationContent}) return decode(configurationContent) // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { @@ -140,6 +141,7 @@ export function parseConfigurationObject( const fallbackOutput = {} as zod.TypeOf const parseResult = schema.safeParse(configurationObject) + // console.log('Config after comparing with schema (includes remote contract)', {parseResult}) if (!parseResult.success) { return abortOrReport( outputContent`\n${outputToken.errorText('Validation errors')} in ${outputToken.path( @@ -346,7 +348,7 @@ export async function loadOpaqueApp(options: { const rawConfig = await loadConfigurationFileContent(configurationPath) const parsed = TemplateConfigSchema.parse(rawConfig) const packageManager = await getPackageManager(appDirectory) - + // console.log('WE ARE NOT GETTING HERE', {rawConfig}) return { state: 'loaded-template', rawConfig, @@ -856,6 +858,7 @@ export async function loadAppConfiguration( options: AppConfigurationLoaderConstructorArgs, ): Promise { const specifications = options.specifications ?? (await loadLocalExtensionsSpecifications()) + console.log('SPECIFICATIONS', {specifications}) const state = await getAppConfigurationState(options.directory, options.userProvidedConfigName) const result = await loadAppConfigurationFromState(state, specifications, options.remoteFlags ?? []) await logMetadataFromAppLoadingProcess(result.configurationLoadResultMetadata) diff --git a/packages/app/src/cli/models/extensions/extension-instance.ts b/packages/app/src/cli/models/extensions/extension-instance.ts index 3a37dd9aaf8..170aabb77e5 100644 --- a/packages/app/src/cli/models/extensions/extension-instance.ts +++ b/packages/app/src/cli/models/extensions/extension-instance.ts @@ -12,6 +12,7 @@ import {PosSpecIdentifier} from './specifications/app_config_point_of_sale.js' import {PrivacyComplianceWebhooksSpecIdentifier} from './specifications/app_config_privacy_compliance_webhooks.js' import {WebhooksSpecIdentifier} from './specifications/app_config_webhook.js' import {WebhookSubscriptionSpecIdentifier} from './specifications/app_config_webhook_subscription.js' +import {HostedAppHomeSpecIdentifier} from './specifications/app_config_hosted_app_home.js' import { ExtensionBuildOptions, buildFunctionExtension, @@ -40,6 +41,7 @@ export const CONFIG_EXTENSION_IDS: string[] = [ AppHomeSpecIdentifier, AppProxySpecIdentifier, BrandingSpecIdentifier, + HostedAppHomeSpecIdentifier, PosSpecIdentifier, PrivacyComplianceWebhooksSpecIdentifier, WebhookSubscriptionSpecIdentifier, @@ -366,6 +368,9 @@ export class ExtensionInstance(spec: { identifier: string schema: ZodSchemaType + buildConfig?: BuildConfig appModuleFeatures?: (config?: TConfiguration) => ExtensionFeature[] transformConfig: TransformationConfig | CustomTransformationConfig uidStrategy?: UidStrategy getDevSessionUpdateMessages?: (config: TConfiguration) => Promise patchWithAppDevURLs?: (config: TConfiguration, urls: ApplicationURLs) => void + copyStaticAssets?: (config: TConfiguration, directory: string, outputPath: string) => Promise }): ExtensionSpecification { const appModuleFeatures = spec.appModuleFeatures ?? (() => []) return createExtensionSpecification({ @@ -256,8 +258,10 @@ export function createConfigExtensionSpecification { + if (!config.static_root) return + const sourceDir = joinPath(directory, config.static_root) + const outputDir = dirname(outputPath) + + return copyDirectoryContents(sourceDir, outputDir).catch((error) => { + throw new Error(`Failed to copy static assets from ${sourceDir} to ${outputDir}: ${error.message}`) + }) + }, +}) + +export default hostedAppHomeSpec diff --git a/packages/app/src/cli/services/dev/app-events/app-event-watcher.ts b/packages/app/src/cli/services/dev/app-events/app-event-watcher.ts index 5a760de6332..313869f0cc6 100644 --- a/packages/app/src/cli/services/dev/app-events/app-event-watcher.ts +++ b/packages/app/src/cli/services/dev/app-events/app-event-watcher.ts @@ -148,6 +148,7 @@ export class AppEventWatcher extends EventEmitter { this.fileWatcher.onChange((events) => { handleWatcherEvents(events, this.app, this.options) .then(async (appEvent) => { + console.log({appEvent}) if (appEvent?.extensionEvents.length === 0) outputDebug('Change detected, but no extensions were affected') if (!appEvent) return @@ -169,6 +170,13 @@ export class AppEventWatcher extends EventEmitter { await this.app.generateExtensionTypes() } + if (appEvent.appWasReloaded) { + const appHomeExtension = this.app.realExtensions.find((ext) => ext.specification.identifier === 'app_home') + if (appHomeExtension) { + await appHomeExtension.copyStaticAssets(this.buildOutputPath) + } + } + // Find deleted extensions and delete their previous build output await this.deleteExtensionsBuildOutput(appEvent) this.emit('all', appEvent) diff --git a/packages/app/src/cli/services/generate/fetch-extension-specifications.ts b/packages/app/src/cli/services/generate/fetch-extension-specifications.ts index 37544a1c672..2087e73763c 100644 --- a/packages/app/src/cli/services/generate/fetch-extension-specifications.ts +++ b/packages/app/src/cli/services/generate/fetch-extension-specifications.ts @@ -38,6 +38,9 @@ export async function fetchSpecifications({ const extensionSpecifications: FlattenedRemoteSpecification[] = result .filter((specification) => ['extension', 'configuration'].includes(specification.experience)) .map((spec) => { + if (spec.identifier === 'hosted_app') { + console.log('Hosted app home spec', spec) + } const newSpec = spec as FlattenedRemoteSpecification // WORKAROUND: The identifiers in the API are different for these extensions to the ones the CLI // has been using so far. This is a workaround to keep the CLI working until the API is updated. @@ -78,7 +81,6 @@ async function mergeLocalAndRemoteSpecs( const merged = {...localSpec, ...remoteSpec, loadedRemoteSpecs: true} as RemoteAwareExtensionSpecification & FlattenedRemoteSpecification - // If configuration is inside an app.toml -- i.e. single UID mode -- we must be able to parse a partial slice. let handleInvalidAdditionalProperties: HandleInvalidAdditionalProperties switch (merged.uidStrategy) {