From a2e6f33d085c58e52da8a1ccc42bd25ee79491a0 Mon Sep 17 00:00:00 2001 From: Piral Release Bot Date: Fri, 8 Nov 2024 09:28:12 +0000 Subject: [PATCH 01/13] Auto update documentation From c2deee1ecae55114ab5ed648aba6b45ed2631723 Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Wed, 13 Nov 2024 10:37:49 +0100 Subject: [PATCH 02/13] Removed --no-save, which is different in npm and other package managers --- CHANGELOG.md | 4 ++++ src/tooling/piral-cli/src/apps/upgrade-pilet.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d2f20b73..aa2f63223 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Piral Changelog +## 1.7.3 (tbd) + +- Fixed `pilet upgrade` command with `npm` client not changing *package.json* + ## 1.7.2 (November 8, 2024) - Fixed removal of `MutationEvent` in recent Chrome in `piral-blazor` (#724) by @dheid diff --git a/src/tooling/piral-cli/src/apps/upgrade-pilet.ts b/src/tooling/piral-cli/src/apps/upgrade-pilet.ts index c87dbf137..3f6731138 100644 --- a/src/tooling/piral-cli/src/apps/upgrade-pilet.ts +++ b/src/tooling/piral-cli/src/apps/upgrade-pilet.ts @@ -144,7 +144,7 @@ export async function upgradePilet(baseDir = process.cwd(), options: UpgradePile if (!monorepoRef) { // only install the latest if the shell does come from remote progress(`Updating npm package to %s ...`, packageRef); - await installNpmPackage(npmClient, packageRef, root, '--no-save'); + await installNpmPackage(npmClient, packageRef, root); } const piralInfo = await readPiralPackage(root, sourceName); From 936744c565691e81a9e3ce914803c42ba369879c Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Thu, 21 Nov 2024 09:55:05 +0100 Subject: [PATCH 03/13] Added --allow-self-signed flag --- CHANGELOG.md | 1 + .../src/apps/add-piral-instance-pilet.ts | 21 +++++++++- src/tooling/piral-cli/src/apps/new-pilet.ts | 20 ++++++++- .../piral-cli/src/apps/publish-pilet.ts | 24 +++++++---- .../piral-cli/src/apps/publish-piral.ts | 17 ++++++-- .../piral-cli/src/apps/run-emulator-piral.ts | 28 ++++++++++--- .../piral-cli/src/apps/upgrade-pilet.ts | 21 +++++++++- src/tooling/piral-cli/src/commands.ts | 42 ++++++++++++++++++- src/tooling/piral-cli/src/common/config.ts | 5 +++ src/tooling/piral-cli/src/common/http.test.ts | 9 ++-- src/tooling/piral-cli/src/common/http.ts | 33 +++++++++++---- src/tooling/piral-cli/src/common/package.ts | 21 +++++----- src/tooling/piral-cli/src/common/release.ts | 5 ++- src/tooling/piral-cli/src/common/shell.ts | 4 +- src/tooling/piral-cli/src/common/website.ts | 18 ++++---- src/tooling/publish-microfrontend/src/http.ts | 25 +++++++---- .../publish-microfrontend/src/index.ts | 13 ++++-- .../publish-microfrontend/src/utils.ts | 7 ++-- 18 files changed, 243 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa2f63223..e2eb66bf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 1.7.3 (tbd) - Fixed `pilet upgrade` command with `npm` client not changing *package.json* +- Added `--allow-self-signed` flag to `piral-cli` commands using HTTP requests ## 1.7.2 (November 8, 2024) diff --git a/src/tooling/piral-cli/src/apps/add-piral-instance-pilet.ts b/src/tooling/piral-cli/src/apps/add-piral-instance-pilet.ts index 4445fe80a..22f4cfc67 100644 --- a/src/tooling/piral-cli/src/apps/add-piral-instance-pilet.ts +++ b/src/tooling/piral-cli/src/apps/add-piral-instance-pilet.ts @@ -16,6 +16,9 @@ import { checkAppShellPackage, ForceOverwrite, copyPiralFiles, + config, + getCertificate, + getAgent, } from '../common'; export interface AddPiralInstancePiletOptions { @@ -39,6 +42,16 @@ export interface AddPiralInstancePiletOptions { */ selected?: boolean; + /** + * Defines a custom certificate for the website emulator. + */ + cert?: string; + + /** + * Allow self-signed certificates. + */ + allowSelfSigned?: boolean; + /** * The npm client to be used when scaffolding. * @example 'yarn' @@ -52,6 +65,8 @@ export const addPiralInstancePiletDefaults: AddPiralInstancePiletOptions = { source: '.', selected: false, npmClient: undefined, + cert: undefined, + allowSelfSigned: config.allowSelfSigned, }; export async function addPiralInstancePilet(baseDir = process.cwd(), options: AddPiralInstancePiletOptions = {}) { @@ -61,6 +76,8 @@ export async function addPiralInstancePilet(baseDir = process.cwd(), options: Ad source = addPiralInstancePiletDefaults.source, selected = addPiralInstancePiletDefaults.selected, app = addPiralInstancePiletDefaults.app, + cert = addPiralInstancePiletDefaults.cert, + allowSelfSigned = addPiralInstancePiletDefaults.allowSelfSigned, } = options; ensure('baseDir', baseDir, 'string'); @@ -72,6 +89,8 @@ export async function addPiralInstancePilet(baseDir = process.cwd(), options: Ad const npmClient = await determineNpmClient(fullBase, defaultNpmClient); const allEntries = await matchAnyPilet(fullBase, [source]); + const ca = await getCertificate(cert); + const agent = getAgent({ ca, allowSelfSigned }); const tasks = allEntries.map(async (entryModule) => { const targetDir = dirname(entryModule); @@ -80,7 +99,7 @@ export async function addPiralInstancePilet(baseDir = process.cwd(), options: Ad if (piletJsonPath) { const piletJsonDir = dirname(piletJsonPath); const root = await findPiletRoot(piletJsonDir); - const packageName = await installPiralInstance(app, fullBase, root, npmClient, selected); + const packageName = await installPiralInstance(app, fullBase, root, npmClient, agent, selected); const piralInfo = await readPiralPackage(root, packageName); const isEmulator = checkAppShellPackage(piralInfo); diff --git a/src/tooling/piral-cli/src/apps/new-pilet.ts b/src/tooling/piral-cli/src/apps/new-pilet.ts index 8830f33c5..dc5ce615b 100644 --- a/src/tooling/piral-cli/src/apps/new-pilet.ts +++ b/src/tooling/piral-cli/src/apps/new-pilet.ts @@ -29,6 +29,8 @@ import { defaultSchemaVersion, piletJsonSchemaUrl, ensure, + getCertificate, + getAgent, } from '../common'; export interface NewPiletOptions { @@ -47,6 +49,16 @@ export interface NewPiletOptions { */ source?: string; + /** + * Defines a custom certificate for the website emulator. + */ + cert?: string; + + /** + * Allow self-signed certificates. + */ + allowSelfSigned?: boolean; + /** * Determines if files should be overwritten by the scaffolding. */ @@ -110,6 +122,8 @@ export const newPiletDefaults: NewPiletOptions = { bundlerName: 'none', variables: {}, name: undefined, + cert: undefined, + allowSelfSigned: config.allowSelfSigned, }; export async function newPilet(baseDir = process.cwd(), options: NewPiletOptions = {}) { @@ -126,6 +140,8 @@ export async function newPilet(baseDir = process.cwd(), options: NewPiletOptions variables = newPiletDefaults.variables, npmClient: defaultNpmClient = newPiletDefaults.npmClient, name = newPiletDefaults.name, + cert = newPiletDefaults.cert, + allowSelfSigned = newPiletDefaults.allowSelfSigned, } = options; ensure('baseDir', baseDir, 'string'); @@ -142,6 +158,8 @@ export async function newPilet(baseDir = process.cwd(), options: NewPiletOptions if (success) { const npmClient = await determineNpmClient(root, defaultNpmClient); + const ca = await getCertificate(cert); + const agent = getAgent({ ca, allowSelfSigned }); const projectName = name || basename(root); progress(`Scaffolding new pilet in %s ...`, root); @@ -196,7 +214,7 @@ always-auth=true`, ); const sourceName = source || `empty-piral@${cliVersion}`; - const packageName = await installPiralInstance(sourceName, fullBase, root, npmClient, true); + const packageName = await installPiralInstance(sourceName, fullBase, root, npmClient, agent, true); const piralInfo = await readPiralPackage(root, packageName); const isEmulator = checkAppShellPackage(piralInfo); const { preScaffold, postScaffold, files, template: preSelectedTemplate } = getPiletsInfo(piralInfo); diff --git a/src/tooling/piral-cli/src/apps/publish-pilet.ts b/src/tooling/piral-cli/src/apps/publish-pilet.ts index 853c4a870..e1ade8170 100644 --- a/src/tooling/piral-cli/src/apps/publish-pilet.ts +++ b/src/tooling/piral-cli/src/apps/publish-pilet.ts @@ -1,3 +1,4 @@ +import { Agent } from 'https'; import { relative, resolve } from 'path'; import { LogLevels, PiletSchemaVersion, PiletPublishSource, PublishScheme } from '../types'; import { @@ -17,6 +18,7 @@ import { triggerBuildPilet, getCertificate, ensure, + getAgent, } from '../common'; export interface PublishPiletOptions { @@ -52,6 +54,11 @@ export interface PublishPiletOptions { * Defines a custom certificate for the feed service. */ cert?: string; + + /** + * Allow self-signed certificates. + */ + allowSelfSigned?: boolean; /** * Sets the schema version of the pilet. Usually, the default one should be picked. @@ -110,7 +117,6 @@ export const publishPiletDefaults: PublishPiletOptions = { url: undefined, apiKey: undefined, fresh: false, - cert: undefined, logLevel: LogLevels.info, schemaVersion: undefined, mode: 'basic', @@ -118,6 +124,8 @@ export const publishPiletDefaults: PublishPiletOptions = { fields: {}, headers: {}, interactive: false, + cert: undefined, + allowSelfSigned: config.allowSelfSigned, }; async function getFiles( @@ -129,7 +137,7 @@ async function getFiles( logLevel: LogLevels, bundlerName: string, _?: Record, - ca?: Buffer, + agent?: Agent, hooks?: PublishPiletOptions['hooks'], ): Promise> { if (fresh) { @@ -181,14 +189,14 @@ async function getFiles( } case 'remote': { log('generalDebug_0003', `Download file from "${sources.join('", "')}".`); - const allFiles = await Promise.all(sources.map((s) => downloadFile(s, ca))); + const allFiles = await Promise.all(sources.map((s) => downloadFile(s, agent))); return allFiles.reduce((result, files) => [...result, ...files], []); } case 'npm': { log('generalDebug_0003', `View npm package "${sources.join('", "')}".`); const allUrls = await Promise.all(sources.map((s) => findNpmTarball(s))); log('generalDebug_0003', `Download file from "${allUrls.join('", "')}".`); - const allFiles = await Promise.all(allUrls.map((url) => downloadFile(url, ca))); + const allFiles = await Promise.all(allUrls.map((url) => downloadFile(url, agent))); return allFiles.reduce((result, files) => [...result, ...files], []); } } @@ -204,11 +212,12 @@ export async function publishPilet(baseDir = process.cwd(), options: PublishPile logLevel = publishPiletDefaults.logLevel, from = publishPiletDefaults.from, schemaVersion = publishPiletDefaults.schemaVersion, - cert = publishPiletDefaults.cert, fields = publishPiletDefaults.fields, headers = publishPiletDefaults.headers, mode = publishPiletDefaults.mode, interactive = publishPiletDefaults.interactive, + cert = publishPiletDefaults.cert, + allowSelfSigned = publishPiletDefaults.allowSelfSigned, _ = {}, hooks = {}, bundlerName, @@ -229,10 +238,11 @@ export async function publishPilet(baseDir = process.cwd(), options: PublishPile } const ca = await getCertificate(cert); + const agent = getAgent({ ca, allowSelfSigned }); log('generalDebug_0003', 'Getting the tgz files ...'); const sources = Array.isArray(source) ? source : [source]; - const files = await getFiles(fullBase, sources, from, fresh, schemaVersion, logLevel, bundlerName, _, ca, hooks); + const files = await getFiles(fullBase, sources, from, fresh, schemaVersion, logLevel, bundlerName, _, agent, hooks); const successfulUploads: Array = []; log('generalDebug_0003', 'Received available tgz files.'); @@ -249,7 +259,7 @@ export async function publishPilet(baseDir = process.cwd(), options: PublishPile if (content) { progress(`Publishing "%s" to "%s" ...`, file, url); - const result = await postFile(url, mode, apiKey, content, fields, headers, ca, interactive); + const result = await postFile(url, mode, apiKey, content, fields, headers, agent, interactive); if (result.success) { successfulUploads.push(file); diff --git a/src/tooling/piral-cli/src/apps/publish-piral.ts b/src/tooling/piral-cli/src/apps/publish-piral.ts index 202f07a55..322e02cf6 100644 --- a/src/tooling/piral-cli/src/apps/publish-piral.ts +++ b/src/tooling/piral-cli/src/apps/publish-piral.ts @@ -25,6 +25,7 @@ import { triggerBuildShell, publishPackageEmulator, ensure, + getAgent, } from '../common'; export interface PublishPiralOptions { @@ -58,6 +59,11 @@ export interface PublishPiralOptions { * Defines a custom certificate for the feed service. */ cert?: string; + + /** + * Allow self-signed certificates. + */ + allowSelfSigned?: boolean; /** * Places additional headers that should be posted to the feed service. @@ -107,10 +113,11 @@ export const publishPiralDefaults: PublishPiralOptions = { interactive: false, apiKey: undefined, fresh: false, - cert: undefined, mode: 'basic', headers: {}, type: 'emulator', + cert: undefined, + allowSelfSigned: config.allowSelfSigned, }; export async function publishPiral(baseDir = process.cwd(), options: PublishPiralOptions = {}) { @@ -121,10 +128,11 @@ export async function publishPiral(baseDir = process.cwd(), options: PublishPira fresh = publishPiralDefaults.fresh, url = config.url ?? publishPiralDefaults.url, apiKey = config.apiKeys?.[url] ?? config.apiKey ?? publishPiralDefaults.apiKey, - cert = publishPiralDefaults.cert, headers = publishPiralDefaults.headers, mode = publishPiralDefaults.mode, type = publishPiralDefaults.type, + cert = publishPiralDefaults.cert, + allowSelfSigned = publishPiralDefaults.allowSelfSigned, _ = {}, hooks = {}, bundlerName, @@ -144,6 +152,7 @@ export async function publishPiral(baseDir = process.cwd(), options: PublishPira } const ca = await getCertificate(cert); + const agent = getAgent({ ca, allowSelfSigned }); log('generalDebug_0003', 'Getting the files ...'); const entryFiles = await retrievePiralRoot(fullBase, './'); @@ -224,7 +233,7 @@ export async function publishPiral(baseDir = process.cwd(), options: PublishPira const files = await matchFiles(targetDir, '**/*'); progress(`Publishing release artifacts to "%s" ...`, url); - const result = await publishWebsiteEmulator(version, url, apiKey, mode, targetDir, files, interactive, headers, ca); + const result = await publishWebsiteEmulator(version, url, apiKey, mode, targetDir, files, interactive, headers, agent); if (!result.success) { fail('failedUploading_0064'); @@ -249,7 +258,7 @@ export async function publishPiral(baseDir = process.cwd(), options: PublishPira const files = await matchFiles(targetDir, '**/*'); progress(`Publishing emulator to "%s" ...`, url); - const result = await publishWebsiteEmulator(version, url, apiKey, mode, targetDir, files, interactive, headers, ca); + const result = await publishWebsiteEmulator(version, url, apiKey, mode, targetDir, files, interactive, headers, agent); if (!result.success) { fail('failedUploading_0064'); diff --git a/src/tooling/piral-cli/src/apps/run-emulator-piral.ts b/src/tooling/piral-cli/src/apps/run-emulator-piral.ts index e377c4d32..1f28c06e0 100644 --- a/src/tooling/piral-cli/src/apps/run-emulator-piral.ts +++ b/src/tooling/piral-cli/src/apps/run-emulator-piral.ts @@ -18,6 +18,8 @@ import { findPiralInstance, determineNpmClient, ensure, + getCertificate, + getAgent, } from '../common'; export interface RunEmulatorPiralOptions { @@ -61,6 +63,16 @@ export interface RunEmulatorPiralOptions { * The package registry to use for resolving the specified Piral app. */ registry?: string; + + /** + * Defines a custom certificate for the website emulator. + */ + cert?: string; + + /** + * Allow self-signed certificates. + */ + allowSelfSigned?: boolean; } export const runEmulatorPiralDefaults: RunEmulatorPiralOptions = { @@ -70,6 +82,8 @@ export const runEmulatorPiralDefaults: RunEmulatorPiralOptions = { strictPort: config.strictPort, registry: config.registry, npmClient: undefined, + cert: undefined, + allowSelfSigned: config.allowSelfSigned, }; function createTempDir() { @@ -94,13 +108,15 @@ export async function runEmulatorPiral(baseDir = process.cwd(), options: RunEmul logLevel = runEmulatorPiralDefaults.logLevel, npmClient: defaultNpmClient = runEmulatorPiralDefaults.npmClient, registry = runEmulatorPiralDefaults.registry, + cert = runEmulatorPiralDefaults.cert, + allowSelfSigned = runEmulatorPiralDefaults.allowSelfSigned, app, feed, } = options; - + ensure('baseDir', baseDir, 'string'); ensure('app', app, 'string'); - + const publicUrl = '/'; const api = config.piletApi; const fullBase = resolve(process.cwd(), baseDir); @@ -114,6 +130,8 @@ export async function runEmulatorPiral(baseDir = process.cwd(), options: RunEmul process.stdin?.setMaxListeners(16); const appRoot = await createTempDir(); + const ca = await getCertificate(cert); + const agent = getAgent({ ca, allowSelfSigned }); if (registry !== runEmulatorPiralDefaults.registry) { progress(`Setting up npm registry (%s) ...`, registry); @@ -128,10 +146,8 @@ always-auth=true`, } const npmClient = await determineNpmClient(appRoot, defaultNpmClient); - const packageName = await installPiralInstance(app, fullBase, appRoot, npmClient); - const piral = await findPiralInstance(packageName, appRoot, { - port: originalPort, - }); + const packageName = await installPiralInstance(app, fullBase, appRoot, npmClient, agent); + const piral = await findPiralInstance(packageName, appRoot, { port: originalPort }, agent); const port = await getAvailablePort(piral.port, strictPort); const krasBaseConfig = resolve(fullBase, krasrc); diff --git a/src/tooling/piral-cli/src/apps/upgrade-pilet.ts b/src/tooling/piral-cli/src/apps/upgrade-pilet.ts index 3f6731138..f7dddaf44 100644 --- a/src/tooling/piral-cli/src/apps/upgrade-pilet.ts +++ b/src/tooling/piral-cli/src/apps/upgrade-pilet.ts @@ -26,6 +26,9 @@ import { getPiletScaffoldData, retrievePiletData, ensure, + config, + getCertificate, + getAgent, } from '../common'; export interface UpgradePiletOptions { @@ -58,6 +61,16 @@ export interface UpgradePiletOptions { */ install?: boolean; + /** + * Defines a custom certificate for the website emulator. + */ + cert?: string; + + /** + * Allow self-signed certificates. + */ + allowSelfSigned?: boolean; + /** * Defines the used npm client. By default, "npm" is used * if no other client is autodetected. The autodetection @@ -79,6 +92,8 @@ export const upgradePiletDefaults: UpgradePiletOptions = { install: true, npmClient: undefined, variables: {}, + cert: undefined, + allowSelfSigned: config.allowSelfSigned, }; export async function upgradePilet(baseDir = process.cwd(), options: UpgradePiletOptions = {}) { @@ -90,6 +105,8 @@ export async function upgradePilet(baseDir = process.cwd(), options: UpgradePile install = upgradePiletDefaults.install, variables = upgradePiletDefaults.variables, npmClient: defaultNpmClient = upgradePiletDefaults.npmClient, + cert = upgradePiletDefaults.cert, + allowSelfSigned = upgradePiletDefaults.allowSelfSigned, } = options; ensure('baseDir', baseDir, 'string'); @@ -106,10 +123,12 @@ export async function upgradePilet(baseDir = process.cwd(), options: UpgradePile } const npmClient = await determineNpmClient(root, defaultNpmClient); + const ca = await getCertificate(cert); + const agent = getAgent({ ca, allowSelfSigned }); // in case we run from a user's CLI we want to allow updating const interactive = isInteractive(); - const { apps, piletPackage } = await retrievePiletData(root, undefined, interactive); + const { apps, piletPackage } = await retrievePiletData(root, undefined, agent, interactive); const { devDependencies = {}, dependencies = {}, source } = piletPackage; if (apps.length === 0) { diff --git a/src/tooling/piral-cli/src/commands.ts b/src/tooling/piral-cli/src/commands.ts index ab42a711c..d274a4eac 100644 --- a/src/tooling/piral-cli/src/commands.ts +++ b/src/tooling/piral-cli/src/commands.ts @@ -218,6 +218,9 @@ const allCommands: Array> = [ .string('ca-cert') .describe('ca-cert', 'Sets a custom certificate authority to use, if any.') .default('ca-cert', apps.publishPiralDefaults.cert) + .boolean('allow-self-signed') + .describe('allow-self-signed', 'Indicates that self-signed certificates should be allowed.') + .default('allow-self-signed', apps.publishPiralDefaults.allowSelfSigned) .number('log-level') .describe('log-level', 'Sets the log level to use (1-5).') .default('log-level', apps.publishPiralDefaults.logLevel) @@ -250,6 +253,7 @@ const allCommands: Array> = [ logLevel: args['log-level'] as LogLevels, apiKey: args['api-key'] as string, cert: args['ca-cert'] as string, + allowSelfSigned: args['allow-self-signed'] as boolean, url: args.url as string, interactive: args.interactive as boolean, mode: args.mode as PublishScheme, @@ -687,6 +691,9 @@ const allCommands: Array> = [ .boolean('interactive') .describe('interactive', 'Defines if authorization tokens can be retrieved interactively.') .default('interactive', apps.publishPiletDefaults.interactive) + .boolean('allow-self-signed') + .describe('allow-self-signed', 'Indicates that self-signed certificates should be allowed.') + .default('allow-self-signed', apps.publishPiletDefaults.allowSelfSigned) .string('base') .default('base', process.cwd()) .describe('base', 'Sets the base directory. By default the current directory is used.'); @@ -698,6 +705,7 @@ const allCommands: Array> = [ url: args.url as string, logLevel: args['log-level'] as LogLevels, cert: args['ca-cert'] as string, + allowSelfSigned: args['allow-self-signed'] as boolean, bundlerName: args.bundler as string, fresh: args.fresh as boolean, from: args.from as PiletPublishSource, @@ -787,6 +795,12 @@ const allCommands: Array> = [ .choices('bundler', bundlerKeys) .describe('bundler', 'Sets the default bundler to install.') .default('bundler', apps.newPiletDefaults.bundlerName) + .string('ca-cert') + .describe('ca-cert', 'Sets a custom certificate authority to use, if any.') + .default('ca-cert', apps.newPiletDefaults.cert) + .boolean('allow-self-signed') + .describe('allow-self-signed', 'Indicates that self-signed certificates should be allowed.') + .default('allow-self-signed', apps.newPiletDefaults.allowSelfSigned) .option('vars', undefined) .describe('vars', 'Sets additional variables to be used when scaffolding.') .default('vars', apps.newPiletDefaults.variables) @@ -811,6 +825,8 @@ const allCommands: Array> = [ bundlerName: args.bundler as string, variables: args.vars as Record, name: args['name'] as string, + cert: args['ca-cert'] as string, + allowSelfSigned: args['allow-self-signed'] as boolean, }); }, }, @@ -819,7 +835,7 @@ const allCommands: Array> = [ alias: ['upgrade'], description: 'Upgrades an existing pilet to the latest version of the used Piral instance.', arguments: ['[target-version]'], - flags(argv) { + flags(argv: any) { return argv .positional('target-version', { type: 'string', @@ -842,6 +858,12 @@ const allCommands: Array> = [ .choices('npm-client', clientTypeKeys) .describe('npm-client', 'Sets the npm client to be used when upgrading.') .default('npm-client', apps.upgradePiletDefaults.npmClient) + .string('ca-cert') + .describe('ca-cert', 'Sets a custom certificate authority to use, if any.') + .default('ca-cert', apps.upgradePiletDefaults.cert) + .boolean('allow-self-signed') + .describe('allow-self-signed', 'Indicates that self-signed certificates should be allowed.') + .default('allow-self-signed', apps.upgradePiletDefaults.allowSelfSigned) .option('vars', undefined) .describe('vars', 'Sets additional variables to be used when scaffolding.') .default('vars', apps.upgradePiletDefaults.variables) @@ -858,6 +880,8 @@ const allCommands: Array> = [ install: args.install as boolean, npmClient: args['npm-client'] as NpmClientType, variables: args.vars as Record, + cert: args['ca-cert'] as string, + allowSelfSigned: args['allow-self-signed'] as boolean, }); }, }, @@ -916,6 +940,12 @@ const allCommands: Array> = [ .boolean('selected') .describe('selected', 'Defines if the provided Piral instance should be selected initially.') .default('selected', apps.addPiralInstancePiletDefaults.selected) + .string('ca-cert') + .describe('ca-cert', 'Sets a custom certificate authority to use, if any.') + .default('ca-cert', apps.addPiralInstancePiletDefaults.cert) + .boolean('allow-self-signed') + .describe('allow-self-signed', 'Indicates that self-signed certificates should be allowed.') + .default('allow-self-signed', apps.addPiralInstancePiletDefaults.allowSelfSigned) .string('base') .default('base', process.cwd()) .describe('base', 'Sets the base directory. By default the current directory is used.'); @@ -927,6 +957,8 @@ const allCommands: Array> = [ npmClient: args['npm-client'] as NpmClientType, app: args.app as string, source: args.source as string, + cert: args['ca-cert'] as string, + allowSelfSigned: args['allow-self-signed'] as boolean, }); }, }, @@ -995,6 +1027,12 @@ const allCommands: Array> = [ .choices('npm-client', clientTypeKeys) .describe('npm-client', 'Sets the npm client to be used when installing the emulator.') .default('npm-client', apps.runEmulatorPiralDefaults.npmClient) + .string('ca-cert') + .describe('ca-cert', 'Sets a custom certificate authority to use, if any.') + .default('ca-cert', apps.runEmulatorPiralDefaults.cert) + .boolean('allow-self-signed') + .describe('allow-self-signed', 'Indicates that self-signed certificates should be allowed.') + .default('allow-self-signed', apps.runEmulatorPiralDefaults.allowSelfSigned) .boolean('open') .describe('open', 'Opens the Piral instance directly in the browser.') .default('open', apps.runEmulatorPiralDefaults.open) @@ -1014,6 +1052,8 @@ const allCommands: Array> = [ logLevel: args['log-level'] as LogLevels, open: args.open as boolean, feed: args.feed as string, + cert: args['ca-cert'] as string, + allowSelfSigned: args['allow-self-signed'] as boolean, }); }, }, diff --git a/src/tooling/piral-cli/src/common/config.ts b/src/tooling/piral-cli/src/common/config.ts index 249e19387..9df93a833 100644 --- a/src/tooling/piral-cli/src/common/config.ts +++ b/src/tooling/piral-cli/src/common/config.ts @@ -73,6 +73,10 @@ export interface PiralCliConfig { * Npm registry. */ registry?: string; + /** + * Allow self-signed certificates. + */ + allowSelfSigned?: boolean; } export const config: PiralCliConfig = rc( @@ -89,6 +93,7 @@ export const config: PiralCliConfig = rc( validators: {}, schemaVersion: 'v2' as const, openBrowser: false, + allowSelfSigned: false, port: 1234, strictPort: false, language: 'ts' as const, diff --git a/src/tooling/piral-cli/src/common/http.test.ts b/src/tooling/piral-cli/src/common/http.test.ts index 210ad6ad2..0e8cdac30 100644 --- a/src/tooling/piral-cli/src/common/http.test.ts +++ b/src/tooling/piral-cli/src/common/http.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vitest } from 'vitest'; -import { postFile, downloadFile } from './http'; +import { postFile, downloadFile, getAgent } from './http'; const apiUrl = 'http://sample.fooo.com/api/v1/pilet'; @@ -80,7 +80,7 @@ vitest.mock('../external', async () => { }, }, }, - FormData: (await vitest.importActual('form-data') as any).default, + FormData: ((await vitest.importActual('form-data')) as any).default, }; }); @@ -155,10 +155,11 @@ describe('HTTP Module', () => { it('downloadFile calls results in error', async () => { errorOther = true; - let result = await downloadFile('http://sample.com/', Buffer.from('example')); + const agent = getAgent({ ca: Buffer.from('example') }); + let result = await downloadFile('http://sample.com/', agent); expect(result.length).toBe(0); errorOther = false; - result = await downloadFile('http://sample.com/', Buffer.from('example')); + result = await downloadFile('http://sample.com/', agent); expect(result.length).toBe(0); }); }); diff --git a/src/tooling/piral-cli/src/common/http.ts b/src/tooling/piral-cli/src/common/http.ts index aba9131da..1b14e7bc1 100644 --- a/src/tooling/piral-cli/src/common/http.ts +++ b/src/tooling/piral-cli/src/common/http.ts @@ -100,8 +100,28 @@ export function getAuthorizationHeaders(scheme: PublishScheme, key: string) { return {}; } -export function downloadFile(target: string, ca?: Buffer): Promise> { - const httpsAgent = ca ? new Agent({ ca }) : undefined; +export interface AgentOptions { + ca?: Buffer; + allowSelfSigned?: boolean; +} + +export async function getDefaultAgent() { + const ca = await getCertificate(); + const allowSelfSigned = config.allowSelfSigned; + return getAgent({ ca, allowSelfSigned }); +} + +export function getAgent({ allowSelfSigned, ca }: AgentOptions) { + if (ca) { + return new Agent({ ca }); + } else if (allowSelfSigned) { + return new Agent({ rejectUnauthorized: false }); + } else { + return undefined; + } +} + +export function downloadFile(target: string, httpsAgent: Agent): Promise> { return axios.default .get(target, { responseType: 'stream', @@ -206,10 +226,9 @@ export async function postForm( key: string, formData: FormDataObj, customHeaders: Record = {}, - ca?: Buffer, + httpsAgent?: Agent, interactive = false, ): Promise { - const httpsAgent = ca ? new Agent({ ca }) : undefined; const form = createAxiosForm(formData); const headers: Record = { @@ -237,7 +256,7 @@ export async function postForm( error, interactive, httpsAgent, - (mode, token) => postForm(target, mode, token, formData, customHeaders, ca, false), + (mode, token) => postForm(target, mode, token, formData, customHeaders, httpsAgent, false), (status, statusText, response) => { if (status === 500) { log('failedHttpPost_0065', response); @@ -266,9 +285,9 @@ export function postFile( file: Buffer, customFields: Record = {}, customHeaders: Record = {}, - ca?: Buffer, + agent?: Agent, interactive = false, ): Promise { const data: FormDataObj = { ...customFields, file: [file, 'pilet.tgz'] }; - return postForm(target, scheme, key, data, customHeaders, ca, interactive); + return postForm(target, scheme, key, data, customHeaders, agent, interactive); } diff --git a/src/tooling/piral-cli/src/common/package.ts b/src/tooling/piral-cli/src/common/package.ts index b7c2f93af..92b7e78cd 100644 --- a/src/tooling/piral-cli/src/common/package.ts +++ b/src/tooling/piral-cli/src/common/package.ts @@ -1,3 +1,4 @@ +import { Agent } from 'https'; import { resolve, join, extname, basename, dirname, relative } from 'path'; import { log, fail } from './log'; import { cliVersion } from './info'; @@ -161,7 +162,8 @@ async function loadPiralInstance(root: string, details?: PiralInstanceDetails): export async function findPiralInstance( proposedApp: string, rootDir: string, - details?: PiralInstanceDetails, + details: PiralInstanceDetails, + agent: Agent, interactive = false, ) { const path = findPackageRoot(proposedApp, rootDir); @@ -172,13 +174,13 @@ export async function findPiralInstance( if (url) { log('generalDebug_0003', `Updating the emulator from remote "${url}" ...`); - await updateFromEmulatorWebsite(root, url, interactive); + await updateFromEmulatorWebsite(root, url, agent, interactive); } return await loadPiralInstance(root, details); } else if (url) { log('generalDebug_0003', `Piral instance not installed yet - trying from remote "${url}" ...`); - const emulator = await scaffoldFromEmulatorWebsite(rootDir, url); + const emulator = await scaffoldFromEmulatorWebsite(rootDir, url, agent); return await loadPiralInstance(emulator.path, details); } @@ -190,6 +192,7 @@ export async function findPiralInstances( piletPackage: PiletPackageData, piletDefinition: undefined | PiletDefinition, rootDir: string, + agent: Agent, interactive?: boolean, ) { if (proposedApps) { @@ -208,7 +211,7 @@ export async function findPiralInstances( if (proposedApps.length > 0) { return Promise.all( proposedApps.map((proposedApp) => - findPiralInstance(proposedApp, rootDir, piletDefinition?.piralInstances?.[proposedApp], interactive), + findPiralInstance(proposedApp, rootDir, piletDefinition?.piralInstances?.[proposedApp], agent, interactive), ), ); } @@ -280,11 +283,7 @@ export async function getPiralPackage(app: string, data: PiralInstanceData, vers }; } -async function getAvailableFiles( - root: string, - name: string, - dirName: string, -): Promise> { +async function getAvailableFiles(root: string, name: string, dirName: string): Promise> { const source = getPiralPath(root, name); const tgz = `${dirName}.tar`; log('generalDebug_0003', `Checking if "${tgz}" exists in "${source}" ...`); @@ -780,13 +779,13 @@ export async function findPiletRoot(proposedRoot: string) { return dirname(packageJsonPath); } -export async function retrievePiletData(target: string, app?: string, interactive?: boolean) { +export async function retrievePiletData(target: string, app?: string, agent?: Agent, interactive?: boolean) { const piletJsonPath = await findFile(target, piletJson); const proposedRoot = piletJsonPath ? dirname(piletJsonPath) : target; const root = await findPiletRoot(proposedRoot); const piletPackage = await readJson(root, packageJson); const piletDefinition: PiletDefinition = piletJsonPath && (await readJson(proposedRoot, piletJson)); - const appPackages = await findPiralInstances(app && [app], piletPackage, piletDefinition, root, interactive); + const appPackages = await findPiralInstances(app && [app], piletPackage, piletDefinition, root, agent, interactive); const apps: Array = []; for (const appPackage of appPackages) { diff --git a/src/tooling/piral-cli/src/common/release.ts b/src/tooling/piral-cli/src/common/release.ts index 6574f99ff..db1302e44 100644 --- a/src/tooling/piral-cli/src/common/release.ts +++ b/src/tooling/piral-cli/src/common/release.ts @@ -1,3 +1,4 @@ +import { Agent } from 'https'; import { basename, dirname, relative } from 'path'; import { readBinary } from './io'; import { publishNpmPackage } from './npm'; @@ -39,7 +40,7 @@ export async function publishWebsiteEmulator( files: Array, interactive: boolean, headers?: Record, - ca?: Buffer, + agent?: Agent, ) { const data: FormDataObj = { version, @@ -53,5 +54,5 @@ export async function publishWebsiteEmulator( data[relPath] = [content, fileName]; } - return await postForm(url, mode, apiKey, data, headers, ca, interactive); + return await postForm(url, mode, apiKey, data, headers, agent, interactive); } diff --git a/src/tooling/piral-cli/src/common/shell.ts b/src/tooling/piral-cli/src/common/shell.ts index ac4c6af42..af2b71306 100644 --- a/src/tooling/piral-cli/src/common/shell.ts +++ b/src/tooling/piral-cli/src/common/shell.ts @@ -1,3 +1,4 @@ +import { Agent } from 'https'; import { progress } from './log'; import { packageJson, piletJson } from './constants'; import { readJson, updateExistingJson, writeJson } from './io'; @@ -55,12 +56,13 @@ export async function installPiralInstance( baseDir: string, rootDir: string, npmClient: NpmClientType, + agent: Agent, selected?: boolean, ): Promise { const [sourceName, sourceVersion, hadVersion, type] = await dissectPackageName(baseDir, usedSource); if (type === 'remote') { - const emulator = await scaffoldFromEmulatorWebsite(rootDir, sourceName); + const emulator = await scaffoldFromEmulatorWebsite(rootDir, sourceName, agent); const packageName = emulator.name; await updatePiletJson(rootDir, packageName, { selected, diff --git a/src/tooling/piral-cli/src/common/website.ts b/src/tooling/piral-cli/src/common/website.ts index 98ef3af0a..4ae4a1bbc 100644 --- a/src/tooling/piral-cli/src/common/website.ts +++ b/src/tooling/piral-cli/src/common/website.ts @@ -1,7 +1,7 @@ import { Agent } from 'https'; import { posix, relative, resolve } from 'path'; import { createPiralStubIndexIfNotExists } from './template'; -import { getAuthorizationHeaders, getAxiosOptions, getCertificate, handleAxiosError } from './http'; +import { getAuthorizationHeaders, getAxiosOptions, handleAxiosError } from './http'; import { packageJson } from './constants'; import { updateConfig } from './config'; import { ForceOverwrite } from './enums'; @@ -11,7 +11,7 @@ import { progress, log } from './log'; import { axios, isInteractive } from '../external'; import { EmulatorWebsiteManifestFiles, EmulatorWebsiteManifest } from '../types'; -async function requestManifest(url: string, interactive: boolean, httpsAgent?: Agent) { +async function requestManifest(url: string, httpsAgent: Agent, interactive: boolean) { const opts = getAxiosOptions(url); try { @@ -26,7 +26,7 @@ async function requestManifest(url: string, interactive: boolean, httpsAgent?: A value: headers.authorization, }, }); - return await requestManifest(url, false, httpsAgent); + return await requestManifest(url, httpsAgent, false); }); } } @@ -105,13 +105,11 @@ async function createEmulatorFiles( await downloadEmulatorFiles(manifestUrl, targetDir, appDir, emulatorJson.files, httpsAgent); } -export async function updateFromEmulatorWebsite(targetDir: string, manifestUrl: string, interactive: boolean) { +export async function updateFromEmulatorWebsite(targetDir: string, manifestUrl: string, httpsAgent: Agent, interactive: boolean) { progress(`Updating emulator from %s ...`, manifestUrl); - const ca = await getCertificate(); - const httpsAgent = ca ? new Agent({ ca }) : undefined; try { - const response = await requestManifest(manifestUrl, interactive, httpsAgent); + const response = await requestManifest(manifestUrl, httpsAgent, interactive); const nextEmulator: EmulatorWebsiteManifest = response.data; const currentEmulator = await readJson(targetDir, packageJson); @@ -130,12 +128,10 @@ export async function updateFromEmulatorWebsite(targetDir: string, manifestUrl: } } -export async function scaffoldFromEmulatorWebsite(rootDir: string, manifestUrl: string) { +export async function scaffoldFromEmulatorWebsite(rootDir: string, manifestUrl: string, httpsAgent: Agent) { progress(`Downloading emulator from %s ...`, manifestUrl); - const ca = await getCertificate(); - const httpsAgent = ca ? new Agent({ ca }) : undefined; const interactive = isInteractive(); - const response = await requestManifest(manifestUrl, interactive, httpsAgent); + const response = await requestManifest(manifestUrl, httpsAgent, interactive); const emulatorJson: EmulatorWebsiteManifest = response.data; const targetDir = resolve(rootDir, 'node_modules', emulatorJson.name); const appDir = resolve(targetDir, 'app'); diff --git a/src/tooling/publish-microfrontend/src/http.ts b/src/tooling/publish-microfrontend/src/http.ts index cbb40782d..0be89a7fe 100644 --- a/src/tooling/publish-microfrontend/src/http.ts +++ b/src/tooling/publish-microfrontend/src/http.ts @@ -34,10 +34,22 @@ export interface PostFormResult { export type FormDataObj = Record; +export interface AgentOptions { + ca?: Buffer; + allowSelfSigned?: boolean; +} -export async function downloadFile(url: string, ca?: Buffer): Promise> { - const httpsAgent = ca ? new Agent({ ca }) : undefined; +export function getAgent({ allowSelfSigned, ca }: AgentOptions) { + if (ca) { + return new Agent({ ca }); + } else if (allowSelfSigned) { + return new Agent({ rejectUnauthorized: false }); + } else { + return undefined; + } +} +export async function downloadFile(url: string, httpsAgent?: Agent): Promise> { try { const res = await axios.get(url, { responseType: 'stream', @@ -58,10 +70,9 @@ export function postForm( key: string, formData: FormDataObj, customHeaders: Record = {}, - ca?: Buffer, + httpsAgent?: Agent, interactive = false, ): Promise { - const httpsAgent = ca ? new Agent({ ca }) : undefined; const form = new FormData(); Object.keys(formData).forEach((key) => { @@ -124,7 +135,7 @@ export function postForm( if (typeof interactiveAuth === 'string') { return getTokenInteractively(interactiveAuth, httpsAgent).then(({ mode, token }) => - postForm(target, mode, token, formData, customHeaders, ca, false), + postForm(target, mode, token, formData, customHeaders, httpsAgent, false), ); } } @@ -173,9 +184,9 @@ export function postFile( file: Buffer, customFields: Record = {}, customHeaders: Record = {}, - ca?: Buffer, + agent?: Agent, interactive = false, ): Promise { const data: FormDataObj = { ...customFields, file: [file, 'microfrontend.tgz'] }; - return postForm(target, scheme, key, data, customHeaders, ca, interactive); + return postForm(target, scheme, key, data, customHeaders, agent, interactive); } diff --git a/src/tooling/publish-microfrontend/src/index.ts b/src/tooling/publish-microfrontend/src/index.ts index 9337542a0..21fe965c6 100644 --- a/src/tooling/publish-microfrontend/src/index.ts +++ b/src/tooling/publish-microfrontend/src/index.ts @@ -7,13 +7,14 @@ import { basename } from 'path'; import { readFile } from 'fs/promises'; import { progress, fail, logDone, logFail, logInfo } from './log'; import { getCa, getFiles } from './utils'; -import { postFile } from './http'; +import { getAgent, postFile } from './http'; const current = process.cwd(); const defaultArgs = rc('microfrontend', { url: undefined, apiKey: undefined, cert: undefined, + allowSelfSigned: false, mode: 'basic', from: 'local', fields: {}, @@ -34,6 +35,9 @@ const args = yargs .string('cert') .describe('cert', 'Sets a custom certificate authority to use, if any.') .default('cert', defaultArgs.cert) + .boolean('allow-self-signed') + .describe('allow-self-signed', 'Indicates that self-signed certificates should be allowed.') + .default('allow-self-signed', defaultArgs.allowSelfSigned) .choices('mode', publishModeKeys) .describe('mode', 'Sets the authorization mode to use.') .default('mode', defaultArgs.mode) @@ -52,10 +56,11 @@ const args = yargs .default('interactive', defaultArgs.interactive).argv; async function run() { - const { cert, source, from, url, 'api-key': apiKey, headers, fields, interactive, mode } = args; + const { cert, source, from, url, 'api-key': apiKey, 'allow-self-signed': allowSelfSigned, headers, fields, interactive, mode } = args; const sources = Array.isArray(source) ? source : [source]; const ca = await getCa(cert); - const files = await getFiles(current, sources, from, ca); + const agent = getAgent({ ca, allowSelfSigned }); + const files = await getFiles(current, sources, from, agent); const successfulUploads: Array = []; if (files.length === 0) { @@ -76,7 +81,7 @@ async function run() { content, fields, headers, - ca, + agent, interactive, ); diff --git a/src/tooling/publish-microfrontend/src/utils.ts b/src/tooling/publish-microfrontend/src/utils.ts index abf51b86e..27568f677 100644 --- a/src/tooling/publish-microfrontend/src/utils.ts +++ b/src/tooling/publish-microfrontend/src/utils.ts @@ -1,4 +1,5 @@ import glob from 'glob'; +import { Agent } from 'https'; import { existsSync, statSync } from 'fs'; import { stat, readFile, readdir, copyFile, rm } from 'fs/promises'; import { dirname, basename, resolve } from 'path'; @@ -83,7 +84,7 @@ export async function getFiles( baseDir: string, sources: Array, from: string, - ca: Buffer, + agent: Agent, ): Promise> { switch (from) { case 'local': { @@ -127,12 +128,12 @@ export async function getFiles( return allMatches.filter(isFile); } case 'remote': { - const allFiles = await Promise.all(sources.map((s) => downloadFile(s, ca))); + const allFiles = await Promise.all(sources.map((s) => downloadFile(s, agent))); return allFiles.reduce((result, files) => [...result, ...files], []); } case 'npm': { const allUrls = await Promise.all(sources.map((s) => findTarball(s))); - const allFiles = await Promise.all(allUrls.map((url) => downloadFile(url, ca))); + const allFiles = await Promise.all(allUrls.map((url) => downloadFile(url, agent))); return allFiles.reduce((result, files) => [...result, ...files], []); } } From dcd813c6e28e2e2995033a83d8e3e092f85a4984 Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Tue, 26 Nov 2024 00:35:02 +0100 Subject: [PATCH 04/13] Updated pidoc --- src/pages/docs/package.json | 2 +- yarn.lock | 67 +++++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/pages/docs/package.json b/src/pages/docs/package.json index 8f341bdba..71d3730ab 100644 --- a/src/pages/docs/package.json +++ b/src/pages/docs/package.json @@ -32,6 +32,6 @@ "test": "echo \"Error: run tests from root\" && exit 1" }, "devDependencies": { - "@pidoc/core": "^0.18.3" + "@pidoc/core": "^0.18.4" } } diff --git a/yarn.lock b/yarn.lock index 20dcda4cb..8a9a31635 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2047,21 +2047,21 @@ dependencies: "@octokit/openapi-types" "^18.0.0" -"@pidoc/components@0.18.3": - version "0.18.3" - resolved "https://registry.yarnpkg.com/@pidoc/components/-/components-0.18.3.tgz#5b4b76ab4db83ceda097a05194f7dc0efd574688" - integrity sha512-SmyH6YQHGmSepH17Dz7evvA5bIekYU0kSEUaBTNibS64Py77PzPa9JXnaFSxK+5s/Drew+YMAYdN/CdACDeOTg== +"@pidoc/components@0.18.4": + version "0.18.4" + resolved "https://registry.yarnpkg.com/@pidoc/components/-/components-0.18.4.tgz#b39c860925684342a538d38c4ebd393f6521d768" + integrity sha512-wC8v1X/Fv12KrnoGf0U1LZenSqrXT3xdiXf5eHq9HMkI8pWng8wTGD1goMJ0pKYimZxW8dIHgo8cPy2OMzToUw== dependencies: flexsearch "0.6.32" stickyfilljs "^2.1.0" -"@pidoc/core@^0.18.3": - version "0.18.3" - resolved "https://registry.yarnpkg.com/@pidoc/core/-/core-0.18.3.tgz#2a139bc8fb797aaad16e7706d08e3b5ebff796c3" - integrity sha512-sLR5Ws6pdXOgRyYseVrdZKdmgaY1rVWQbWlhJTp3kaKxaz719bP+ZDK1k7jN/L+b4UFENSSL53moNZzqEUbcMw== +"@pidoc/core@^0.18.4": + version "0.18.4" + resolved "https://registry.yarnpkg.com/@pidoc/core/-/core-0.18.4.tgz#1cad7f92a23598d1b2c9478b6cc980d13269879f" + integrity sha512-eA6WUhW5TJvYqek0lWT4J9e4LENiAgAlPhzTIzszQYBBT1Q/D9qhOrnlE0oWYt7Y/Gb2ctJdYqa9VRblgU5U9A== dependencies: "@asciidoctor/core" "^3.0.4" - "@pidoc/components" "0.18.3" + "@pidoc/components" "0.18.4" chokidar "^3.6.0" keyword-extractor "0.0.28" markdown-it "^14.1.0" @@ -2082,9 +2082,9 @@ markdown-it-sup "^2.0.0" markdown-it-task-checkbox "^1.0.6" markdown-it-video "^0.6.3" - pug "^3.0.2" - yaml "^2.4.1" - yargs "^15.4.1" + pug "^3" + yaml "^2" + yargs "^17" "@pkgjs/parseargs@^0.11.0": version "0.11.0" @@ -9917,7 +9917,7 @@ pug-walk@^2.0.0: resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-2.0.0.tgz#417aabc29232bb4499b5b5069a2b2d2a24d5f5fe" integrity sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ== -pug@^3.0.2: +pug@^3: version "3.0.3" resolved "https://registry.yarnpkg.com/pug/-/pug-3.0.3.tgz#e18324a314cd022883b1e0372b8af3a1a99f7597" integrity sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g== @@ -11084,7 +11084,16 @@ stop-iteration-iterator@^1.0.0: dependencies: internal-slot "^1.0.4" -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -11129,7 +11138,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -11150,6 +11159,13 @@ strip-ansi@^5.1.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -12216,7 +12232,7 @@ workerpool@^3.1.1: object-assign "4.1.1" rsvp "^4.8.4" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -12234,6 +12250,15 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" @@ -12344,10 +12369,10 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^2.4.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.0.tgz#c6165a721cf8000e91c36490a41d7be25176cf5d" - integrity sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw== +yaml@^2: + version "2.6.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.1.tgz#42f2b1ba89203f374609572d5349fb8686500773" + integrity sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg== yargs-parser@21.1.1, yargs-parser@^21.1.1: version "21.1.1" @@ -12367,7 +12392,7 @@ yargs-parser@^20.2.2, yargs-parser@^20.2.3: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs@17.7.2, yargs@^17.2.1, yargs@^17.6.2: +yargs@17.7.2, yargs@^17, yargs@^17.2.1, yargs@^17.6.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== From a55ea0fc163e1880e25001191f6dc2fbbe2034a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 23:36:18 +0000 Subject: [PATCH 05/13] Bump cross-spawn from 7.0.3 to 7.0.6 Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6. - [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md) - [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6) --- updated-dependencies: - dependency-name: cross-spawn dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8a9a31635..3f4db40ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4810,9 +4810,9 @@ create-react-class@^15.6.0: object-assign "^4.1.1" cross-spawn@^7.0.0, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" From 03997d34765047396350ecddc6e49e05695f4371 Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Tue, 3 Dec 2024 11:55:32 +0100 Subject: [PATCH 06/13] Fixed website emulator --- CHANGELOG.md | 1 + src/tooling/piral-cli/src/common/website.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2eb66bf1..b8ab231fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 1.7.3 (tbd) - Fixed `pilet upgrade` command with `npm` client not changing *package.json* +- Fixed shared dependency list from website emulator to exclude legacy dependencies - Added `--allow-self-signed` flag to `piral-cli` commands using HTTP requests ## 1.7.2 (November 8, 2024) diff --git a/src/tooling/piral-cli/src/common/website.ts b/src/tooling/piral-cli/src/common/website.ts index 4ae4a1bbc..3f248893b 100644 --- a/src/tooling/piral-cli/src/common/website.ts +++ b/src/tooling/piral-cli/src/common/website.ts @@ -92,6 +92,7 @@ async function createEmulatorFiles( peerDependencies: {}, optionalDependencies: emulatorJson.dependencies.optional, devDependencies: emulatorJson.dependencies.included, + sharedDependencies: [Object.keys(emulatorJson.importmap.imports)], }, true, ); From 7ffe6d9f3fc8f20bbd7f1278db5ad311c1eff759 Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Tue, 3 Dec 2024 22:55:18 +0100 Subject: [PATCH 07/13] Added support for React Router v7 --- CHANGELOG.md | 1 + .../src/defaults/DefaultRouteSwitch_v7.tsx | 20 ++++ .../src/defaults/DefaultRouter_v7.tsx | 9 ++ .../piral-core/src/defaults/navigator_v7.tsx | 97 +++++++++++++++++++ src/framework/piral-core/src/tools/codegen.ts | 11 ++- 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/framework/piral-core/src/defaults/DefaultRouteSwitch_v7.tsx create mode 100644 src/framework/piral-core/src/defaults/DefaultRouter_v7.tsx create mode 100644 src/framework/piral-core/src/defaults/navigator_v7.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index b8ab231fa..27e39af66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Fixed `pilet upgrade` command with `npm` client not changing *package.json* - Fixed shared dependency list from website emulator to exclude legacy dependencies - Added `--allow-self-signed` flag to `piral-cli` commands using HTTP requests +- Added support for `react-router` v7 ## 1.7.2 (November 8, 2024) diff --git a/src/framework/piral-core/src/defaults/DefaultRouteSwitch_v7.tsx b/src/framework/piral-core/src/defaults/DefaultRouteSwitch_v7.tsx new file mode 100644 index 000000000..b6bd35182 --- /dev/null +++ b/src/framework/piral-core/src/defaults/DefaultRouteSwitch_v7.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +//@ts-ignore +import { Routes, Route } from 'react-router'; +import { RouteSwitchProps } from '../types'; + +export const DefaultRouteSwitch: React.FC = ({ paths, NotFound, ...props }) => { + return ( + + {paths.map(({ path, Component }) => ( + //@ts-ignore + } /> + ))} + { + //@ts-ignore + } /> + } + + ); +}; +DefaultRouteSwitch.displayName = 'DefaultRouteSwitch'; diff --git a/src/framework/piral-core/src/defaults/DefaultRouter_v7.tsx b/src/framework/piral-core/src/defaults/DefaultRouter_v7.tsx new file mode 100644 index 000000000..6d091bc4f --- /dev/null +++ b/src/framework/piral-core/src/defaults/DefaultRouter_v7.tsx @@ -0,0 +1,9 @@ +import * as React from 'react'; +//@ts-ignore +import { BrowserRouter } from 'react-router'; +import { RouterProps } from '../types'; + +export const DefaultRouter: React.FC = ({ children, publicPath }) => { + return {children}; +}; +DefaultRouter.displayName = 'DefaultRouter'; diff --git a/src/framework/piral-core/src/defaults/navigator_v7.tsx b/src/framework/piral-core/src/defaults/navigator_v7.tsx new file mode 100644 index 000000000..cfbfc5aa7 --- /dev/null +++ b/src/framework/piral-core/src/defaults/navigator_v7.tsx @@ -0,0 +1,97 @@ +import * as React from 'react'; +//@ts-ignore +import { UNSAFE_NavigationContext as RouterContext, Navigate, useLocation } from 'react-router'; +import { NavigationApi } from '../types'; + +let _nav: any; +const _noop = () => {}; + +export function useRouterContext() { + return React.useContext(RouterContext); +} + +export function useCurrentNavigation() { + const ctx: any = useRouterContext(); + const location = useLocation(); + + React.useEffect(() => { + if (_nav) { + window.dispatchEvent( + new CustomEvent('piral-navigate', { + detail: { + location, + }, + }), + ); + } + }, [location]); + + React.useEffect(() => { + _nav = ctx.navigator; + + return () => { + _nav = undefined; + }; + }, []); +} + +export function createRedirect(to: string) { + return () => ; +} + +export function createNavigation(publicPath: string): NavigationApi { + const enhance = (info) => ({ + ...info, + location: { + get href() { + return _nav.createHref(info.location); + }, + ...info.location, + }, + }); + + return { + get path() { + const loc = _nav ? _nav.location : location; + return loc.pathname; + }, + get url() { + const loc = _nav ? _nav.location : location; + return `${loc.pathname}${loc.search}${loc.hash}`; + }, + push(target, state) { + if (_nav) { + _nav.push(target, state); + } + }, + replace(target, state) { + if (_nav) { + _nav.replace(target, state); + } + }, + go(n) { + if (_nav) { + _nav.go(n); + } + }, + block(blocker) { + if (!_nav) { + return _noop; + } + return _nav.block((transition) => blocker(enhance(transition))); + }, + listen(listener) { + const handler = (e: CustomEvent) => listener(enhance(e.detail)); + + window.addEventListener('piral-navigate', handler); + + return () => { + window.removeEventListener('piral-navigate', handler); + }; + }, + get router() { + return _nav; + }, + publicPath, + }; +} diff --git a/src/framework/piral-core/src/tools/codegen.ts b/src/framework/piral-core/src/tools/codegen.ts index 2962f1b25..da4ea0b69 100644 --- a/src/framework/piral-core/src/tools/codegen.ts +++ b/src/framework/piral-core/src/tools/codegen.ts @@ -164,17 +164,26 @@ export function createDefaultState(imports: Array, exports: Array Date: Wed, 4 Dec 2024 00:48:51 +0100 Subject: [PATCH 08/13] Fixed emulator path --- CHANGELOG.md | 1 + src/tooling/piral-cli/src/common/emulator.ts | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27e39af66..88c3efc0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Fixed `pilet upgrade` command with `npm` client not changing *package.json* - Fixed shared dependency list from website emulator to exclude legacy dependencies +- Fixed issue with relative app path in emulator package generated on Windows - Added `--allow-self-signed` flag to `piral-cli` commands using HTTP requests - Added support for `react-router` v7 diff --git a/src/tooling/piral-cli/src/common/emulator.ts b/src/tooling/piral-cli/src/common/emulator.ts index 269a0cc6c..84705121f 100644 --- a/src/tooling/piral-cli/src/common/emulator.ts +++ b/src/tooling/piral-cli/src/common/emulator.ts @@ -1,4 +1,4 @@ -import { join, resolve, relative, basename, extname } from 'path'; +import { join, resolve, relative, basename, posix } from 'path'; import { findDependencyVersion, copyScaffoldingFiles, isValidDependency, flattenExternals } from './package'; import { createPiralStubIndexIfNotExists } from './template'; import { filesTar, filesOnceTar, packageJson, piralJson, emulatorJson } from './constants'; @@ -139,9 +139,9 @@ export async function createEmulatorSources( version: cliVersion, generated: true, }, - main: `./${join(appDir, 'index.js')}`, - typings: `./${join(appDir, 'index.d.ts')}`, - app: `./${join(appDir, 'index.html')}`, + main: `./${posix.join(appDir, 'index.js')}`, + typings: `./${posix.join(appDir, 'index.d.ts')}`, + app: `./${posix.join(appDir, 'index.html')}`, peerDependencies: {}, optionalDependencies, devDependencies: { From 38ba013166d64fb445d285462c980427f5c37d99 Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Wed, 4 Dec 2024 10:52:05 +0100 Subject: [PATCH 09/13] Integrate bluesky --- .github/workflows/twitter-release.yml | 6 ++++++ .github/workflows/twitter-tip.yml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/twitter-release.yml b/.github/workflows/twitter-release.yml index 3e383031f..31bbfa4a4 100644 --- a/.github/workflows/twitter-release.yml +++ b/.github/workflows/twitter-release.yml @@ -17,3 +17,9 @@ jobs: consumer-secret: ${{ secrets.TWITTER_CONSUMER_API_SECRET }} access-token: ${{ secrets.TWITTER_ACCESS_TOKEN }} access-token-secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} + - uses: smapiot/send-bluesky-post-action@v1 + name: Bluesky post new release + with: + status: "New ${{ github.event.repository.name }} release ${{ github.event.release.tag_name }}! ${{ github.event.release.html_url }} #microfrontends #piral #react #release" + bluesky-email: ${{ secrets.BLUESKY_EMAIL }} + bluesky-password: ${{ secrets.BLUESKY_PASSWORD }} diff --git a/.github/workflows/twitter-tip.yml b/.github/workflows/twitter-tip.yml index 994084b72..08406e96d 100644 --- a/.github/workflows/twitter-tip.yml +++ b/.github/workflows/twitter-tip.yml @@ -23,3 +23,9 @@ jobs: consumer-secret: ${{ secrets.TWITTER_CONSUMER_API_SECRET }} access-token: ${{ secrets.TWITTER_ACCESS_TOKEN }} access-token-secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} + - uses: smapiot/send-bluesky-post-action@v1 + name: Bluesky post daily tip + with: + status: "${{ steps.tweet.outputs.TIP }} #piral #dailytips #microfrontends" + bluesky-email: ${{ secrets.BLUESKY_EMAIL }} + bluesky-password: ${{ secrets.BLUESKY_PASSWORD }} From 2b059e3e3bc77d1d7c56e04d29d0a0f815769162 Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Fri, 6 Dec 2024 01:12:53 +0100 Subject: [PATCH 10/13] Also post on Bluesky --- .github/workflows/twitter-release.yml | 2 +- .github/workflows/twitter-tip.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/twitter-release.yml b/.github/workflows/twitter-release.yml index 31bbfa4a4..e20b3ff9c 100644 --- a/.github/workflows/twitter-release.yml +++ b/.github/workflows/twitter-release.yml @@ -17,7 +17,7 @@ jobs: consumer-secret: ${{ secrets.TWITTER_CONSUMER_API_SECRET }} access-token: ${{ secrets.TWITTER_ACCESS_TOKEN }} access-token-secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} - - uses: smapiot/send-bluesky-post-action@v1 + - uses: smapiot/send-bluesky-post-action@v2 name: Bluesky post new release with: status: "New ${{ github.event.repository.name }} release ${{ github.event.release.tag_name }}! ${{ github.event.release.html_url }} #microfrontends #piral #react #release" diff --git a/.github/workflows/twitter-tip.yml b/.github/workflows/twitter-tip.yml index 08406e96d..17f056554 100644 --- a/.github/workflows/twitter-tip.yml +++ b/.github/workflows/twitter-tip.yml @@ -23,7 +23,7 @@ jobs: consumer-secret: ${{ secrets.TWITTER_CONSUMER_API_SECRET }} access-token: ${{ secrets.TWITTER_ACCESS_TOKEN }} access-token-secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} - - uses: smapiot/send-bluesky-post-action@v1 + - uses: smapiot/send-bluesky-post-action@v2 name: Bluesky post daily tip with: status: "${{ steps.tweet.outputs.TIP }} #piral #dailytips #microfrontends" From 06f4f2d31e37542c2ddd036f3cffd87c6bc3097c Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Mon, 9 Dec 2024 01:45:44 +0100 Subject: [PATCH 11/13] Include Vite6 as an option --- src/tooling/piral-cli/src/common/constants.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tooling/piral-cli/src/common/constants.ts b/src/tooling/piral-cli/src/common/constants.ts index 4c293b10a..aeaaf7dfe 100644 --- a/src/tooling/piral-cli/src/common/constants.ts +++ b/src/tooling/piral-cli/src/common/constants.ts @@ -29,6 +29,7 @@ export const bundlerNames = [ 'webpack5' as const, 'vite' as const, 'vite5' as const, + 'vite6' as const, 'xbuild' as const, ]; export const declarationEntryExtensions = ['.html', '.pug', ...entryModuleExtensions]; From 4d4edf9b3090958d68aa13988ddf13603f9e43f1 Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Mon, 9 Dec 2024 18:16:34 +0100 Subject: [PATCH 12/13] Improvements and fixes for npm client resolution --- src/tooling/piral-cli/src/common/npm.ts | 134 +++++++++++------- src/tooling/piral-cli/src/common/shell.ts | 6 +- .../piral-cli/src/npm-clients/index.ts | 27 +++- src/tooling/piral-cli/src/types/internal.ts | 26 +++- src/tooling/piral-cli/src/types/public.ts | 6 +- 5 files changed, 138 insertions(+), 61 deletions(-) diff --git a/src/tooling/piral-cli/src/common/npm.ts b/src/tooling/piral-cli/src/common/npm.ts index 8e6bab679..5b5a2159c 100644 --- a/src/tooling/piral-cli/src/common/npm.ts +++ b/src/tooling/piral-cli/src/common/npm.ts @@ -5,10 +5,10 @@ import { config } from './config'; import { legacyCoreExternals, frameworkLibs, defaultRegistry, packageJson } from './constants'; import { inspectPackage } from './inspect'; import { readJson, checkExists } from './io'; -import { clients, detectClients, isWrapperClient } from '../npm-clients'; +import { clients, detectDirectClients, detectWrapperClients, isDirectClient, isWrapperClient } from '../npm-clients'; import { clientTypeKeys } from '../helpers'; import { getModulePath } from '../external'; -import { PackageType, NpmClientType } from '../types'; +import { PackageType, NpmClientType, NpmClient, NpmDirectClientType, NpmWapperClientType } from '../types'; const gitPrefix = 'git+'; const filePrefix = 'file:'; @@ -63,56 +63,88 @@ async function detectMonorepoRoot(root: string): Promise<[] | [string, NpmClient return []; } -/** - * For details about how this works consult issue - * https://github.com/smapiot/piral/issues/203 - * @param root The project's root directory. - */ -export async function determineNpmClient(root: string, selected?: NpmClientType): Promise { - if (!selected || !clientTypeKeys.includes(selected)) { - log('generalDebug_0003', 'No npm client selected. Checking for lock or config files ...'); +async function determineWrapperClient(root: string): Promise { + const searchedClients = await detectWrapperClients(root); + const foundClients = searchedClients.filter((m) => m.result).map((m) => m.client); - const searchedClients = await detectClients(root); - const foundClients = searchedClients.filter((m) => m.result); - - log( - 'generalDebug_0003', - `Results of the lock file check: ${searchedClients.map((m) => `${m.client}=${m.result}`).join(', ')}`, - ); + if (foundClients.length > 0) { + const [client] = foundClients; if (foundClients.length > 1) { - const wrapperClient = foundClients.find((m) => isWrapperClient(m.client)); - - if (wrapperClient) { - const { client } = wrapperClient; - log('generalDebug_0003', `Found valid wrapper client via lock or config file: "${client}".`); - } + log( + 'generalWarning_0001', + `Found multiple clients via their lock or config files: "${foundClients.join('", "')}".`, + ); } - if (foundClients.length > 0) { - const { client } = foundClients[0]; + log('generalDebug_0003', `Found valid direct client via lock or config file: "${client}".`); + return client; + } - if (foundClients.length > 1) { - const clientStr = `"${foundClients.map((m) => m.client).join('", "')}"`; - log('generalWarning_0001', `Found multiple clients via their lock or config files: ${clientStr}.`); - } + const defaultClient = config.npmClient; - log('generalDebug_0003', `Found valid direct client via lock or config file: "${client}".`); - return client; - } + if (isWrapperClient(defaultClient)) { + log('generalDebug_0003', `Using the default client: "${defaultClient}".`); + return defaultClient; + } + + return undefined; +} - const defaultClient = config.npmClient; +async function determineDirectClient(root: string): Promise { + const searchedClients = await detectDirectClients(root); + const foundClients = searchedClients.filter((m) => m.result).map((m) => m.client); - if (clientTypeKeys.includes(defaultClient)) { - log('generalDebug_0003', `Using the default client: "${defaultClient}".`); - return defaultClient; + if (foundClients.length > 0) { + const [client] = foundClients; + + if (foundClients.length > 1) { + log( + 'generalWarning_0001', + `Found multiple clients via their lock or config files: "${foundClients.join('", "')}".`, + ); } - log('generalDebug_0003', 'Using the fallback "npm" client.'); - return 'npm'; + log('generalDebug_0003', `Found valid direct client via lock or config file: "${client}".`); + return client; + } + + const defaultClient = config.npmClient; + + if (isDirectClient(defaultClient)) { + log('generalDebug_0003', `Using the default client: "${defaultClient}".`); + return defaultClient; } - return selected; + log('generalDebug_0003', 'Using the fallback "npm" client.'); + return 'npm'; +} + +/** + * For details about how this works consult issue + * https://github.com/smapiot/piral/issues/203 + * @param root The project's root directory. + */ +export async function determineNpmClient(root: string, selected?: NpmClientType): Promise { + if (!selected || !clientTypeKeys.includes(selected)) { + log('generalDebug_0003', 'No npm client selected. Checking for lock or config files ...'); + const [direct, wrapper] = await Promise.all([determineDirectClient(root), determineWrapperClient(root)]); + return { + direct, + wrapper, + }; + } else if (isDirectClient(selected)) { + return { + proposed: selected, + direct: selected, + }; + } else { + return { + proposed: selected, + direct: await determineDirectClient(root), + wrapper: selected, + }; + } } export async function isMonorepoPackageRef(refName: string, root: string): Promise { @@ -126,35 +158,37 @@ export async function isMonorepoPackageRef(refName: string, root: string): Promi return false; } -export function installNpmDependencies(client: NpmClientType, target = '.'): Promise { - const { installDependencies } = clients[client]; +export function installNpmDependencies(client: NpmClient, target = '.'): Promise { + const { installDependencies } = clients[client.direct]; return installDependencies(target); } export async function installNpmPackageFromOptionalRegistry( packageRef: string, - target = '.', + target: string, registry: string, ): Promise { + const client = await determineNpmClient(target, 'npm'); + try { - await installNpmPackage('npm', packageRef, target, '--registry', registry); + await installNpmPackage(client, packageRef, target, '--registry', registry); } catch (e) { if (registry === defaultRegistry) { throw e; } - await installNpmPackage('npm', packageRef, target, '--registry', defaultRegistry); + await installNpmPackage(client, packageRef, target, '--registry', defaultRegistry); } } export async function uninstallNpmPackage( - client: NpmClientType, + client: NpmClient, packageRef: string, target = '.', ...flags: Array ): Promise { try { - const { uninstallPackage } = clients[client]; + const { uninstallPackage } = clients[client.direct]; return await uninstallPackage(packageRef, target, ...flags); } catch (ex) { log( @@ -166,13 +200,13 @@ export async function uninstallNpmPackage( } export async function installNpmPackage( - client: NpmClientType, + client: NpmClient, packageRef: string, target = '.', ...flags: Array ): Promise { try { - const { installPackage } = clients[client]; + const { installPackage } = clients[client.direct]; return await installPackage(packageRef, target, ...flags); } catch (ex) { log( @@ -183,8 +217,8 @@ export async function installNpmPackage( } } -export function initNpmProject(client: NpmClientType, projectName: string, target: string) { - const { initProject } = clients[client]; +export function initNpmProject(client: NpmClient, projectName: string, target: string) { + const { initProject } = clients[client.wrapper]; return initProject(projectName, target); } diff --git a/src/tooling/piral-cli/src/common/shell.ts b/src/tooling/piral-cli/src/common/shell.ts index af2b71306..1b0b2bba9 100644 --- a/src/tooling/piral-cli/src/common/shell.ts +++ b/src/tooling/piral-cli/src/common/shell.ts @@ -5,7 +5,7 @@ import { readJson, updateExistingJson, writeJson } from './io'; import { scaffoldFromEmulatorWebsite } from './website'; import { combinePackageRef, getPackageName, getPackageVersion } from './npm'; import { dissectPackageName, installNpmPackage, isLinkedPackage } from './npm'; -import { NpmClientType, PackageType, PiralInstanceDetails } from '../types'; +import { NpmClient, PackageType, PiralInstanceDetails } from '../types'; async function updatePiletJson(target: string, appName: string, appDetails: PiralInstanceDetails) { const oldContent = await readJson(target, piletJson); @@ -30,7 +30,7 @@ async function setupPiralInstance( hadVersion: boolean, rootDir: string, sourceVersion: string, - npmClient: NpmClientType, + npmClient: NpmClient, ) { if (!isLinkedPackage(sourceName, type, hadVersion, rootDir)) { const packageRef = combinePackageRef(sourceName, sourceVersion, type); @@ -55,7 +55,7 @@ export async function installPiralInstance( usedSource: string, baseDir: string, rootDir: string, - npmClient: NpmClientType, + npmClient: NpmClient, agent: Agent, selected?: boolean, ): Promise { diff --git a/src/tooling/piral-cli/src/npm-clients/index.ts b/src/tooling/piral-cli/src/npm-clients/index.ts index a90ea1e30..5114660db 100644 --- a/src/tooling/piral-cli/src/npm-clients/index.ts +++ b/src/tooling/piral-cli/src/npm-clients/index.ts @@ -1,5 +1,6 @@ import { dirname, resolve } from 'path'; import { findFile } from '../common/io'; +import type { NpmClientType, NpmDirectClientType, NpmWapperClientType } from '../types'; import * as lerna from './lerna'; import * as npm from './npm'; @@ -19,20 +20,26 @@ export const clients = { bun, }; -type ClientName = keyof typeof clients; +const directClients: Array = ['npm', 'pnp', 'yarn', 'pnpm', 'bun']; +const wrapperClients: Array = ['lerna', 'rush']; -const directClients = ['npm', 'pnp', 'yarn', 'pnpm', 'bun']; +export function isWrapperClient(client: NpmClientType): client is NpmWapperClientType { + return wrapperClients.includes(client as any); +} -export function isWrapperClient(client: ClientName) { - return !directClients.includes(client); +export function isDirectClient(client: NpmClientType): client is NpmDirectClientType { + return directClients.includes(client as any); } -export async function detectClients(root: string) { +async function detectClients( + root: string, + clientNames: Array, +): Promise> { const packageJson = await findFile(resolve(root, '..'), 'package.json'); const stopDir = packageJson ? dirname(packageJson) : undefined; return await Promise.all( - Object.keys(clients).map(async (client: ClientName) => { + clientNames.map(async (client) => { const result = await clients[client].detectClient(root, stopDir); return { client, @@ -41,3 +48,11 @@ export async function detectClients(root: string) { }), ); } + +export function detectDirectClients(root: string) { + return detectClients(root, directClients); +} + +export function detectWrapperClients(root: string) { + return detectClients(root, wrapperClients); +} diff --git a/src/tooling/piral-cli/src/types/internal.ts b/src/tooling/piral-cli/src/types/internal.ts index 2aee89914..83f7f3c68 100644 --- a/src/tooling/piral-cli/src/types/internal.ts +++ b/src/tooling/piral-cli/src/types/internal.ts @@ -1,5 +1,11 @@ import type { LogLevels } from './common'; -import type { ImportmapVersions, PiletSchemaVersion } from './public'; +import type { + ImportmapVersions, + NpmClientType, + NpmDirectClientType, + NpmWapperClientType, + PiletSchemaVersion, +} from './public'; export interface PiralInstanceDetails { selected?: boolean; @@ -34,3 +40,21 @@ export interface FileInfo { * 2. The (short) error message */ export type QuickMessage = [LogLevels, string, string]; + +/** + * Result of identifying an npm client in a project. + */ +export interface NpmClient { + /** + * The proposed client - can be anything. + */ + proposed?: NpmClientType; + /** + * The direct npm client. + */ + direct: NpmDirectClientType; + /** + * The wrapper npm client, if any. + */ + wrapper?: NpmWapperClientType; +} diff --git a/src/tooling/piral-cli/src/types/public.ts b/src/tooling/piral-cli/src/types/public.ts index 93552ae78..6d0c9e67a 100644 --- a/src/tooling/piral-cli/src/types/public.ts +++ b/src/tooling/piral-cli/src/types/public.ts @@ -261,7 +261,11 @@ export type PiletBuildType = 'default' | 'standalone' | 'manifest'; export type PackageType = 'registry' | 'file' | 'git' | 'remote'; -export type NpmClientType = 'npm' | 'yarn' | 'pnp' | 'pnpm' | 'lerna' | 'rush' | 'bun'; +export type NpmDirectClientType = 'npm' | 'yarn' | 'pnp' | 'pnpm' | 'bun'; + +export type NpmWapperClientType = 'lerna' | 'rush'; + +export type NpmClientType = NpmDirectClientType | NpmWapperClientType; export type Framework = 'piral' | 'piral-core' | 'piral-base'; From 28cf0e674658da4dabcef9bede5d5f1444e151e3 Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Mon, 9 Dec 2024 22:50:50 +0100 Subject: [PATCH 13/13] Improved tests --- src/tooling/piral-cli/src/common/npm.test.ts | 32 ++++++++++---------- src/tooling/piral-cli/src/common/npm.ts | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/tooling/piral-cli/src/common/npm.test.ts b/src/tooling/piral-cli/src/common/npm.test.ts index b87bf6e1e..02491a456 100644 --- a/src/tooling/piral-cli/src/common/npm.test.ts +++ b/src/tooling/piral-cli/src/common/npm.test.ts @@ -202,39 +202,39 @@ describe('npm Module', () => { it('installs a package using the npm command line tool without a target', async () => { wrongCase = false; - await installNpmPackage('npm', 'foo', 'latest').then((result) => expect(result).toEqual(jsonValueString)); + await installNpmPackage({ direct: 'npm' }, 'foo', 'latest').then((result) => expect(result).toEqual(jsonValueString)); wrongCase = true; - await installNpmPackage('npm', 'foo', 'latest').then((result) => expect(result).not.toEqual(jsonValueString)); + await installNpmPackage({ direct: 'npm' }, 'foo', 'latest').then((result) => expect(result).not.toEqual(jsonValueString)); }); it('installs a package using the npm command line tool without a version', async () => { wrongCase = false; - await installNpmPackage('npm', 'foo').then((result) => expect(result).toEqual(jsonValueString)); + await installNpmPackage({ direct: 'npm' }, 'foo').then((result) => expect(result).toEqual(jsonValueString)); wrongCase = true; - await installNpmPackage('npm', 'foo').then((result) => expect(result).not.toEqual(jsonValueString)); + await installNpmPackage({ direct: 'npm' }, 'foo').then((result) => expect(result).not.toEqual(jsonValueString)); }); it('installs a package using the Yarn command line tool without a version', async () => { wrongCase = false; - await installNpmPackage('yarn', 'foo').then((result) => expect(result).toEqual(jsonValueString)); + await installNpmPackage({ direct: 'yarn' }, 'foo').then((result) => expect(result).toEqual(jsonValueString)); wrongCase = true; - await installNpmPackage('yarn', 'foo').then((result) => expect(result).not.toEqual(jsonValueString)); + await installNpmPackage({ direct: 'yarn' }, 'foo').then((result) => expect(result).not.toEqual(jsonValueString)); }); it('installs a package using the Pnpm command line tool without a version', async () => { wrongCase = false; - await installNpmPackage('pnpm', 'foo').then((result) => expect(result).toEqual(jsonValueString)); + await installNpmPackage({ direct: 'pnpm' }, 'foo').then((result) => expect(result).toEqual(jsonValueString)); wrongCase = true; - await installNpmPackage('pnpm', 'foo').then((result) => expect(result).not.toEqual(jsonValueString)); + await installNpmPackage({ direct: 'pnpm' }, 'foo').then((result) => expect(result).not.toEqual(jsonValueString)); }); it('installs a package using the npm command line tool with some flag', async () => { wrongCase = false; - await installNpmPackage('npm', 'foo', '1.3', '.', '--a=b').then((result) => + await installNpmPackage({ direct: 'pnpm' }, 'foo', '1.3', '.', '--a=b').then((result) => expect(result).toEqual(jsonValueString), ); wrongCase = true; - await installNpmPackage('npm', 'foo', '1.3', '.', '--a=b').then((result) => + await installNpmPackage({ direct: 'pnpm' }, 'foo', '1.3', '.', '--a=b').then((result) => expect(result).not.toEqual(jsonValueString), ); }); @@ -281,23 +281,23 @@ describe('npm Module', () => { it('install dependencies with npm client', async () => { wrongCase = false; - await installNpmDependencies('npm').then((result) => expect(result).toEqual(jsonValueString)); + await installNpmDependencies({ direct: 'npm' }).then((result) => expect(result).toEqual(jsonValueString)); wrongCase = true; - await installNpmDependencies('npm').then((result) => expect(result).not.toEqual(jsonValueString)); + await installNpmDependencies({ direct: 'npm' }).then((result) => expect(result).not.toEqual(jsonValueString)); }); it('install dependencies with pnpm client', async () => { wrongCase = false; - await installNpmDependencies('pnpm').then((result) => expect(result).toEqual(jsonValueString)); + await installNpmDependencies({ direct: 'pnpm' }).then((result) => expect(result).toEqual(jsonValueString)); wrongCase = true; - await installNpmDependencies('pnpm').then((result) => expect(result).not.toEqual(jsonValueString)); + await installNpmDependencies({ direct: 'pnpm' }).then((result) => expect(result).not.toEqual(jsonValueString)); }); it('install dependencies with yarn client', async () => { wrongCase = false; - await installNpmDependencies('yarn').then((result) => expect(result).toEqual(jsonValueString)); + await installNpmDependencies({ direct: 'yarn' }).then((result) => expect(result).toEqual(jsonValueString)); wrongCase = true; - await installNpmDependencies('yarn').then((result) => expect(result).not.toEqual(jsonValueString)); + await installNpmDependencies({ direct: 'yarn' }).then((result) => expect(result).not.toEqual(jsonValueString)); }); it('create npm package', async () => { diff --git a/src/tooling/piral-cli/src/common/npm.ts b/src/tooling/piral-cli/src/common/npm.ts index 5b5a2159c..094a79c4a 100644 --- a/src/tooling/piral-cli/src/common/npm.ts +++ b/src/tooling/piral-cli/src/common/npm.ts @@ -218,7 +218,7 @@ export async function installNpmPackage( } export function initNpmProject(client: NpmClient, projectName: string, target: string) { - const { initProject } = clients[client.wrapper]; + const { initProject } = clients[client.wrapper || client.direct]; return initProject(projectName, target); }