diff --git a/CHANGELOG.md b/CHANGELOG.md index 1841c24b..114df088 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +### [2.2.3-stage.2](https://github.com/aziontech/lib/compare/v2.2.3-stage.1...v2.2.3-stage.2) (2025-11-06) + + +### Bug Fixes + +* implement custom WASM loader for Nuxt SSR builds (#307) ([3fec9d8](https://github.com/aziontech/lib/commit/3fec9d8919e52d2df983f35676d5af7a6e2156a9)) + +### [2.2.3-stage.1](https://github.com/aziontech/lib/compare/v2.2.2...v2.2.3-stage.1) (2025-11-06) + + +### Bug Fixes + +* update mtls attribute in workload configuration (#306) ([f6bc044](https://github.com/aziontech/lib/commit/f6bc044344b1c5e9919b48576125b816183d75ee)) + ### [2.2.2](https://github.com/aziontech/lib/compare/v2.2.1...v2.2.2) (2025-10-29) diff --git a/package-lock.json b/package-lock.json index f619462b..0a4585d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "azion", - "version": "2.1.4", + "version": "2.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "azion", - "version": "2.1.4", + "version": "2.2.2", "license": "MIT", "workspaces": [ "packages/*" diff --git a/package.json b/package.json index 75c13005..7309bb99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "azion", - "version": "2.2.2", + "version": "2.2.3-stage.2", "description": "Azion Packages for Edge Computing.", "scripts": { "prepare": "husky", diff --git a/packages/config/src/configProcessor/helpers/azion.config.example.ts b/packages/config/src/configProcessor/helpers/azion.config.example.ts index f9283ee9..4de9fa6c 100644 --- a/packages/config/src/configProcessor/helpers/azion.config.example.ts +++ b/packages/config/src/configProcessor/helpers/azion.config.example.ts @@ -532,9 +532,12 @@ const config: AzionConfig = { }, }, mtls: { - verification: 'enforce' as WorkloadMTLSVerification, - certificate: 67890, - crl: [1, 2, 3], + enabled: true, + config: { + verification: 'enforce' as WorkloadMTLSVerification, + certificate: 67890, + crl: [1, 2, 3], + }, }, deployments: [ { diff --git a/packages/config/src/configProcessor/helpers/schema.ts b/packages/config/src/configProcessor/helpers/schema.ts index 954c01f7..8453b16e 100644 --- a/packages/config/src/configProcessor/helpers/schema.ts +++ b/packages/config/src/configProcessor/helpers/schema.ts @@ -987,22 +987,31 @@ const azionConfigSchema = { mtls: { type: 'object', properties: { - verification: { - type: 'string', - enum: WORKLOAD_MTLS_VERIFICATION, - default: 'enforce', + enabled: { + type: 'boolean', + default: false, }, - certificate: { - type: ['integer', 'null'], - minimum: 1, - }, - crl: { - type: ['array', 'null'], - items: { type: 'integer' }, - maxItems: 100, + config: { + type: 'object', + properties: { + verification: { + type: 'string', + enum: WORKLOAD_MTLS_VERIFICATION, + default: 'enforce', + }, + certificate: { + type: ['integer', 'null'], + minimum: 1, + }, + crl: { + type: ['array', 'null'], + items: { type: 'integer' }, + maxItems: 100, + }, + }, + additionalProperties: false, }, }, - required: ['verification'], additionalProperties: false, }, deployments: { diff --git a/packages/config/src/configProcessor/helpers/schemaManifest.ts b/packages/config/src/configProcessor/helpers/schemaManifest.ts index af889930..179cf28b 100644 --- a/packages/config/src/configProcessor/helpers/schemaManifest.ts +++ b/packages/config/src/configProcessor/helpers/schemaManifest.ts @@ -1309,22 +1309,31 @@ const schemaWorkloadManifest = { mtls: { type: 'object', properties: { - verification: { - type: 'string', - enum: WORKLOAD_MTLS_VERIFICATION, - default: 'enforce', - }, - certificate: { - type: ['integer', 'null'], - minimum: 1, + enabled: { + type: 'boolean', + default: false, }, - crl: { - type: ['array', 'null'], - items: { type: 'integer' }, - maxItems: 100, + config: { + type: 'object', + properties: { + verification: { + type: 'string', + enum: WORKLOAD_MTLS_VERIFICATION, + default: 'enforce', + }, + certificate: { + type: ['integer', 'null'], + minimum: 1, + }, + crl: { + type: ['array', 'null'], + items: { type: 'integer' }, + maxItems: 100, + }, + }, + additionalProperties: false, }, }, - required: ['verification'], additionalProperties: false, }, }, diff --git a/packages/config/src/configProcessor/processStrategy/implementations/workloadProcessConfigStrategy.test.ts b/packages/config/src/configProcessor/processStrategy/implementations/workloadProcessConfigStrategy.test.ts index 9b54b336..c26a7ce5 100644 --- a/packages/config/src/configProcessor/processStrategy/implementations/workloadProcessConfigStrategy.test.ts +++ b/packages/config/src/configProcessor/processStrategy/implementations/workloadProcessConfigStrategy.test.ts @@ -81,9 +81,12 @@ describe('WorkloadProcessConfigStrategy', () => { }, }, mtls: { - verification: 'permissive', - certificate: 456, - crl: [789], + enabled: true, + config: { + verification: 'permissive', + certificate: 456, + crl: [789], + }, }, }, ], @@ -112,9 +115,12 @@ describe('WorkloadProcessConfigStrategy', () => { }, }, mtls: { - verification: 'permissive', - certificate: 456, - crl: [789], + enabled: true, + config: { + verification: 'permissive', + certificate: 456, + crl: [789], + }, }, }), ]); @@ -232,9 +238,12 @@ describe('WorkloadProcessConfigStrategy', () => { }, }, mtls: { - verification: 'permissive', - certificate: 456, - crl: [789], + enabled: true, + config: { + verification: 'permissive', + certificate: 456, + crl: [789], + }, }, }, ], @@ -264,9 +273,12 @@ describe('WorkloadProcessConfigStrategy', () => { }, }, mtls: { - verification: 'permissive', - certificate: 456, - crl: [789], + enabled: true, + config: { + verification: 'permissive', + certificate: 456, + crl: [789], + }, }, }), ], @@ -352,7 +364,7 @@ describe('WorkloadProcessConfigStrategy', () => { }; const result = strategy.transformToConfig(payload) as { - workloads: Array<{ mtls?: { verification: string; certificate?: number | null; crl?: number[] | null } }>; + workloads: Array<{ mtls?: { enabled?: false; config?: { verification: string; certificate?: number | null; crl?: number[] | null } } }>; }; expect(result.workloads[0].mtls).toBeUndefined(); diff --git a/packages/config/src/configProcessor/processStrategy/implementations/workloadProcessConfigStrategy.ts b/packages/config/src/configProcessor/processStrategy/implementations/workloadProcessConfigStrategy.ts index 513c10ba..002b317a 100644 --- a/packages/config/src/configProcessor/processStrategy/implementations/workloadProcessConfigStrategy.ts +++ b/packages/config/src/configProcessor/processStrategy/implementations/workloadProcessConfigStrategy.ts @@ -33,9 +33,12 @@ class WorkloadProcessConfigStrategy extends ProcessConfigStrategy { }, mtls: workload.mtls ? { - verification: workload.mtls.verification || 'enforce', - certificate: workload.mtls.certificate, - crl: workload.mtls.crl, + enabled: workload.mtls.enabled || false, + config: { + verification: workload.mtls.config.verification || 'enforce', + certificate: workload.mtls.config.certificate, + crl: workload.mtls.config.crl, + }, } : undefined, })); @@ -68,9 +71,12 @@ class WorkloadProcessConfigStrategy extends ProcessConfigStrategy { }, mtls: workload.mtls ? { - verification: workload.mtls.verification, - certificate: workload.mtls.certificate, - crl: workload.mtls.crl, + enabled: workload.mtls.enabled || false, + config: { + verification: workload.mtls.config.verification || 'enforce', + certificate: workload.mtls.config.certificate, + crl: workload.mtls.config.crl, + }, } : undefined, })); diff --git a/packages/config/src/types.ts b/packages/config/src/types.ts index 697a9b61..6c66ec9d 100644 --- a/packages/config/src/types.ts +++ b/packages/config/src/types.ts @@ -776,9 +776,12 @@ export type AzionWorkloadProtocols = { }; export type AzionWorkloadMTLS = { - verification: WorkloadMTLSVerification; - certificate?: number | null; - crl?: number[] | null; + enabled: boolean; + config: { + verification: WorkloadMTLSVerification; + certificate?: number | null; + crl?: number[] | null; + }; }; /** diff --git a/packages/presets/docs/preset-nuxt.md b/packages/presets/docs/preset-nuxt.md index fe575f83..37c27289 100644 --- a/packages/presets/docs/preset-nuxt.md +++ b/packages/presets/docs/preset-nuxt.md @@ -41,6 +41,28 @@ export default defineNuxtConfig({ }); ``` +### Using nuxt-og-image with SSR + +If you're using `nuxt-og-image` in your project with SSR, you need to add the following configuration to your `nuxt.config.ts`: + +```typescript +export default defineNuxtConfig({ + modules: ['nuxt-og-image'], + nitro: { + preset: require.resolve('azion/preset/nuxt/ssr'), + }, + ogImage: { + compatibility: { + runtime: { + resvg: 'wasm', + }, + }, + }, +}); +``` + +This configuration ensures that the `resvg` library uses the WASM runtime, which is compatible with the Azion edge environment. + ## Configuration SSG Configure your `nuxt.config.ts` to use the Azion SSG preset: diff --git a/packages/presets/src/presets/nuxt/nitro/ssr/index.js b/packages/presets/src/presets/nuxt/nitro/ssr/index.js index 444a29f4..8001c6c0 100644 --- a/packages/presets/src/presets/nuxt/nitro/ssr/index.js +++ b/packages/presets/src/presets/nuxt/nitro/ssr/index.js @@ -1,6 +1,7 @@ import { writeFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { resolve } from 'pathe'; +import rollupWasmLoader from './plugins/rollup-wasm-loader'; export default { extends: 'base-worker', @@ -18,10 +19,16 @@ export default { }, }, wasm: { - lazy: false, - esmImport: true, + lazy: true, }, hooks: { + 'build:before': (nitro) => { + nitro.options.rollupConfig.plugins.push( + rollupWasmLoader({ + outputDir: `${nitro.options.output.dir}/public`, + }), + ); + }, async compiled(nitro) { await writeFile( resolve(nitro.options.output.dir, 'package.json'), diff --git a/packages/presets/src/presets/nuxt/nitro/ssr/plugins/rollup-wasm-loader.js b/packages/presets/src/presets/nuxt/nitro/ssr/plugins/rollup-wasm-loader.js new file mode 100644 index 00000000..9f5b9382 --- /dev/null +++ b/packages/presets/src/presets/nuxt/nitro/ssr/plugins/rollup-wasm-loader.js @@ -0,0 +1,123 @@ +/* eslint-disable */ +import { copyFileSync, existsSync, mkdirSync } from 'node:fs'; +import { basename, dirname, resolve } from 'node:path'; + +export function rollupWasmLoader(options = {}) { + const { outputDir = '.output/public' } = options; + + return { + name: 'rollup-wasm-loader', + enforce: 'pre', + + resolveId(id, importer) { + // Intercepts WASM file imports + if (id.includes('.wasm')) { + let cleanId = id; + + cleanId = cleanId.replace('unwasm:external:', ''); + cleanId = cleanId.replace('unwasm:', ''); + cleanId = cleanId.replace(/\x00/g, ''); + cleanId = cleanId.split('?')[0]; + + if (cleanId.length > 100) { + const wasmMatch = cleanId.match(/([^\/\\-]+)\.wasm/); + if (wasmMatch) { + cleanId = `${wasmMatch[1]}.wasm`; + } + } + + let wasmPath = cleanId; + + if (cleanId.startsWith('@') || cleanId.includes('node_modules')) { + const packageMatch = cleanId.match(/(@[^/]+\/[^/]+|[^/]+)\/(.+)/); + if (packageMatch) { + wasmPath = resolve(process.cwd(), 'node_modules', packageMatch[1], packageMatch[2]); + } else { + wasmPath = resolve(process.cwd(), 'node_modules', cleanId); + } + } else if (importer && !cleanId.startsWith('/')) { + try { + wasmPath = resolve(dirname(importer.replace(/\x00/g, '')), cleanId); + } catch { + wasmPath = resolve(process.cwd(), 'node_modules', cleanId); + } + } + + console.log(`[rollup-wasm-loader] Intercepting: ${id.substring(0, 50)}... -> ${cleanId}`); + console.log(`[rollup-wasm-loader] Resolved path: ${wasmPath}`); + + return `\0wasm:${basename(cleanId)}:${wasmPath}`; + } + + return null; + }, + + load(id) { + if (id.startsWith('\0wasm:')) { + const parts = id.replace('\0wasm:', '').split(':'); + const fileName = parts[0]; + const sourcePath = parts[1]; + + console.log(`[rollup-wasm-loader] Processing: ${fileName}`); + console.log(`[rollup-wasm-loader] Source path: ${sourcePath}`); + console.log(`[rollup-wasm-loader] File exists: ${sourcePath ? existsSync(sourcePath) : 'N/A'}`); + + if (sourcePath && existsSync(sourcePath)) { + try { + const destDir = resolve(process.cwd(), outputDir); + const destPath = resolve(destDir, fileName); + + console.log(`[rollup-wasm-loader] Destination directory: ${destDir}`); + console.log(`[rollup-wasm-loader] Destination file: ${destPath}`); + + if (!existsSync(destDir)) { + mkdirSync(destDir, { recursive: true }); + console.log(`[rollup-wasm-loader] Directory created: ${destDir}`); + } + + // Copy file + copyFileSync(sourcePath, destPath); + console.log(`[rollup-wasm-loader] ✅ Copied: ${sourcePath} -> ${destPath}`); + + // Verify if it was copied + if (existsSync(destPath)) { + console.log(`[rollup-wasm-loader] ✅ Confirmed: file exists at ${destPath}`); + } else { + console.error(`[rollup-wasm-loader] ❌ Error: file was not copied to ${destPath}`); + } + } catch (error) { + console.error(`[rollup-wasm-loader] ❌ Error copying ${fileName}:`, error.message); + console.error(`[rollup-wasm-loader] Stack:`, error.stack); + } + } else { + console.warn(`[rollup-wasm-loader] ⚠️ Source file not found: ${sourcePath}`); + console.warn(`[rollup-wasm-loader] ⚠️ Generating reference without copy for: ${fileName}`); + } + + // Return simple code that only exports file:/// + return { + code: `export default 'file:///${fileName}';`, + map: null, + }; + } + + return null; + }, + + transform(code, id) { + // Block any unwasm transformation + if ( + id.startsWith('\0wasm:') || + id.includes('.wasm') || + id.includes('wasm/') || + /[a-f0-9]{16}-[a-f0-9]{16}\.wasm/.test(id) + ) { + return { code, map: null }; + } + + return null; + }, + }; +} + +export default rollupWasmLoader;