From ee9729df350f80050c7cad5804ef5860b390459d Mon Sep 17 00:00:00 2001 From: ivanbenko Date: Wed, 1 Apr 2026 20:48:26 +0200 Subject: [PATCH 1/2] fix(docker-compose): resolve module paths at load time for Pulumi dynamic provider Pre-resolve and remap module paths to compiled .js files so they survive Pulumi's closure serialization in the MirrorState dynamic provider. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../fix-mirror-state-dynamic-provider.md | 5 ++++ .../src/mirror-state/mirror-state.ts | 24 +++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 .changeset/fix-mirror-state-dynamic-provider.md diff --git a/.changeset/fix-mirror-state-dynamic-provider.md b/.changeset/fix-mirror-state-dynamic-provider.md new file mode 100644 index 0000000..8e51e6b --- /dev/null +++ b/.changeset/fix-mirror-state-dynamic-provider.md @@ -0,0 +1,5 @@ +--- +'@opsen/docker-compose': patch +--- + +Fix MirrorStateProvider dynamic provider module resolution to survive Pulumi closure serialization diff --git a/packages/docker-compose/src/mirror-state/mirror-state.ts b/packages/docker-compose/src/mirror-state/mirror-state.ts index 35663d7..486a292 100644 --- a/packages/docker-compose/src/mirror-state/mirror-state.ts +++ b/packages/docker-compose/src/mirror-state/mirror-state.ts @@ -1,15 +1,25 @@ import { dynamic, type CustomResourceOptions } from '@pulumi/pulumi' import type { MirrorStateProviderInputs, MirrorStateInputs } from './types' -// Imported dynamically inside provider methods to avoid capturing module -// references in Pulumi's closure serialization (breaks with pnpm store paths). type ServerModule = typeof import('./server') type CommonModule = typeof import('./common') +// Resolve absolute paths at module load time so they survive Pulumi's closure +// serialization. The dynamic provider runs plain Node.js (no tsx), so paths must +// point to compiled .js files in dist/. When loaded via tsx from src/, remap accordingly. +function resolveForDynamicProvider(relativePath: string): string { + + let resolved = require.resolve(relativePath) + resolved = resolved.replace(/\.ts$/, '.js').replace(/\/src\//, '/dist/') + return resolved +} +const serverPath = resolveForDynamicProvider('./server') +const commonPath = resolveForDynamicProvider('./common') + export class MirrorStateProvider implements dynamic.ResourceProvider { async create(inputs: MirrorStateProviderInputs): Promise { // eslint-disable-next-line @typescript-eslint/no-require-imports - const server: ServerModule = require('./server') + const server: ServerModule = require(serverPath) const hash = await server.sendData(inputs) return { id: `${inputs.connection.user}: ${inputs.remotePath}`, @@ -23,7 +33,7 @@ export class MirrorStateProvider implements dynamic.ResourceProvider { news: MirrorStateProviderInputs, ): Promise { // eslint-disable-next-line @typescript-eslint/no-require-imports - const server: ServerModule = require('./server') + const server: ServerModule = require(serverPath) const hash = await server.sendData(news) return { outs: { ...news, filesHash: hash } } } @@ -34,9 +44,9 @@ export class MirrorStateProvider implements dynamic.ResourceProvider { news: MirrorStateProviderInputs, ): Promise { // eslint-disable-next-line @typescript-eslint/no-require-imports - const server: ServerModule = require('./server') + const server: ServerModule = require(serverPath) // eslint-disable-next-line @typescript-eslint/no-require-imports - const common: CommonModule = require('./common') + const common: CommonModule = require(commonPath) try { const remoteState = await server.getData(news) return { @@ -55,7 +65,7 @@ export class MirrorStateProvider implements dynamic.ResourceProvider { async delete(_id: string, props: MirrorStateProviderInputs): Promise { // eslint-disable-next-line @typescript-eslint/no-require-imports - const server: ServerModule = require('./server') + const server: ServerModule = require(serverPath) await server.removeData(props) } } From 7f9d093c67f2927a2b904a044aaf2e581d7a928c Mon Sep 17 00:00:00 2001 From: ivanbenko Date: Wed, 1 Apr 2026 20:51:19 +0200 Subject: [PATCH 2/2] style(docker-compose): fix prettier formatting in mirror-state Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/docker-compose/src/mirror-state/mirror-state.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/docker-compose/src/mirror-state/mirror-state.ts b/packages/docker-compose/src/mirror-state/mirror-state.ts index 486a292..0009222 100644 --- a/packages/docker-compose/src/mirror-state/mirror-state.ts +++ b/packages/docker-compose/src/mirror-state/mirror-state.ts @@ -8,7 +8,6 @@ type CommonModule = typeof import('./common') // serialization. The dynamic provider runs plain Node.js (no tsx), so paths must // point to compiled .js files in dist/. When loaded via tsx from src/, remap accordingly. function resolveForDynamicProvider(relativePath: string): string { - let resolved = require.resolve(relativePath) resolved = resolved.replace(/\.ts$/, '.js').replace(/\/src\//, '/dist/') return resolved