Skip to content

Commit eb76bdc

Browse files
committed
Improve organization with Claude
1 parent 1fa3314 commit eb76bdc

File tree

23 files changed

+437
-244
lines changed

23 files changed

+437
-244
lines changed

packages/cli/index.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import {
1414
resolveHooks,
1515
resolveAppToLaunch,
1616
UserConfig,
17-
valid
17+
valid,
18+
19+
// Errors
20+
CommonersError,
1821
} from '@commoners/solidarity'
1922

2023
import pkg from './package.json' assert { type: 'json' }
@@ -143,14 +146,15 @@ cli
143146
.option('--public', 'Launch your service as public (services only)')
144147

145148
.action(async (root, options) => {
146-
const { config: configPath, service, public: isPublic, port, stdin, ...overrides } = options
147-
const isOnlyServices = !overrides.target && service // Services take priority if specified
149+
try {
150+
const { config: configPath, service, public: isPublic, port, stdin, ...overrides } = options
151+
const isOnlyServices = !overrides.target && service // Services take priority if specified
148152

149-
preprocessTarget(overrides.target, cliHooks)
150-
const config = await getConfig({ root, config: configPath, stdin })
151-
if (!config) return failed('Configuration not found')
152-
const reconciledConfig = reconcile(config, overrides) as UserConfig
153-
const hooks = await resolveHooks(reconciledConfig.hooks, cliHooks) // Default hooks
153+
preprocessTarget(overrides.target, cliHooks)
154+
const config = await getConfig({ root, config: configPath, stdin })
155+
if (!config) return failed('Configuration not found')
156+
const reconciledConfig = reconcile(config, overrides) as UserConfig
157+
const hooks = await resolveHooks(reconciledConfig.hooks, cliHooks) // Default hooks
154158

155159
let launchSpinner
156160
const start = message => {
@@ -207,11 +211,18 @@ cli
207211
}
208212
}
209213

210-
// Ensure services are not specified with a target
211-
else if (service) return failed(`Cannot specify both services and a launch target`, `Specify either a target or services to launch`)
214+
// Ensure services are not specified with a target
215+
else if (service) return failed(`Cannot specify both services and a launch target`, `Specify either a target or services to launch`)
212216

213-
// Enhanced launch feedback
214-
await launch({ ...reconciledConfig, hooks })
217+
// Enhanced launch feedback
218+
await launch({ ...reconciledConfig, hooks })
219+
} catch (error) {
220+
if (error instanceof CommonersError) {
221+
ui.error(error.message, error.details)
222+
process.exit(1)
223+
}
224+
throw error // Re-throw unexpected errors
225+
}
215226
})
216227

217228
// Build the application using the specified settings

packages/core/assets/electron/main.ts

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,10 @@ runVerification().then(async isValid => {
146146
try {
147147
if (this.isDestroyed()) return // Do not send messages to destroyed windows
148148
return this.webContents.send(channel, ...args)
149-
} catch (e) {} // Catch in case messages are registered as sendable for a window that has been closed
149+
} catch (e) {
150+
// Window may have been closed - this is expected and safe to ignore
151+
console.debug(`Failed to send message to channel ${channel}:`, e instanceof Error ? e.message : e)
152+
}
150153
}
151154

152155
type ReadyFunction = (win: BrowserWindow) => any
@@ -593,10 +596,6 @@ runVerification().then(async isValid => {
593596
__location.hash = urlObj.hash
594597

595598
await loadPage(win, urlObj.pathname) // Required for successful navigation relative to the root (e.g. "../..")
596-
597-
// // NOTE: This does not work when using loadFile
598-
// const pageIdentifier = urlObj.pathname + urlObj.search + urlObj.hash
599-
// loadPage(win, pageIdentifier) // Required for successful navigation relative to the root (e.g. "../..")
600599
})
601600

602601
Object.defineProperty(win, '__show', {
@@ -731,15 +730,6 @@ runVerification().then(async isValid => {
731730
await boundRunAppPlugins([resolvedServices]) // Run plugins on start with resolved services
732731

733732
app.whenReady().then(async () => {
734-
// session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
735-
// console.log(`[CSP] Headers received for ${details.url}`)
736-
// callback({
737-
// responseHeaders: {
738-
// ...details.responseHeaders
739-
// }
740-
// })
741-
// })
742-
743733
// ------------------------ STDIN Commands ------------------------
744734

745735
const rl = createInterface({
@@ -792,8 +782,6 @@ runVerification().then(async isValid => {
792782
const { protocol, net } = electron
793783
app.setAppUserModelId(`com.${scheme}`)
794784

795-
// console.log("Registered protocol", protocolOptions)
796-
797785
protocol.handle(scheme, req => {
798786
const loadedURL = new URL(req.url)
799787
const { host, pathname, search, hash } = loadedURL

packages/core/assets/services/env/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ export function tryStatSync(file: string): Stats | undefined {
1111
// The "throwIfNoEntry" is a performance optimization for cases where the file does not exist
1212
return statSync(file, { throwIfNoEntry: false })
1313
} catch {
14-
// Ignore errors
14+
// File doesn't exist or cannot be accessed
15+
return undefined
1516
}
1617
}
1718

packages/core/assets/services/index.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,6 @@ export async function start(
339339

340340
const resolvedURL = new URL(config.url)
341341

342-
// const host = getLocalIP() // Constrain to local IP address if not public
343342
resolvedURL.hostname = config.public ? '0.0.0.0' : resolvedURL.hostname
344343

345344
hooks.emit({ type: 'service:launch:start', service: label, filepath })
@@ -413,7 +412,6 @@ export async function start(
413412
hooks.emit({ type: 'service:exit', service: label, code })
414413
})
415414

416-
// process.on('close', (code) => code === null ? console.log(chalk.gray(`Restarting ${label}...`)) : console.error(chalk.red(`[${label}] exited with code ${code}`)));
417415

418416
hooks.emit({ type: 'service:launch:complete', service: label, url: resolvedURL.href, filepath })
419417
processes[id] = childProcess
@@ -429,7 +427,7 @@ const killProcess = p => {
429427
try {
430428
return p.kill()
431429
} catch (e) {
432-
console.error(e)
430+
console.error(`Failed to kill process ${p.pid}:`, e instanceof Error ? e.message : e)
433431
}
434432
}
435433

packages/core/assets/utils/icons.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { safePath } from './paths.js'
22

33
// Copied types
4+
import type { IconType as ImportedIconType } from '../../types.js'
45
type BaseIconType = string | string[]
56
function tuple<T extends string[]>(...o: T) {
67
return o
78
}
89

910
const valid = tuple('light', 'dark')
10-
type IconType = BaseIconType | Record<(typeof valid)[number], BaseIconType>
11+
type IconType = ImportedIconType
1112

1213
const isIconValue = o => typeof o === 'string' || Array.isArray(o)
1314

@@ -34,7 +35,7 @@ const getPreferredIcon = (
3435

3536
// Get icon safely
3637
type IconOptions = {
37-
type?: (typeof valid.icon)[number]
38+
type?: (typeof valid)[number]
3839
preferredFormats?: string[]
3940
}
4041

@@ -57,7 +58,7 @@ export const getIcon = (icon: IconType, options: IconOptions = {}) => {
5758
}
5859

5960
// Get first valid icon
60-
const found = valid.icon.find(str => isIconValue(icon[str]))
61+
const found = valid.find(str => isIconValue(icon[str]))
6162
const resolved = found ? icon[found] : Object.values(icon).find(isIconValue)
6263
return resolved ? getPreferredIcon(resolved, preferredFormats) : resolved
6364
}

packages/core/assets/utils/index.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,6 @@ export function isPluginLoadable(plugin) {
3636
return isPluginFeatureSupported.call(this, plugin, 'load')
3737
}
3838

39-
// const commonPluginFeatures = [ 'load', 'start', 'ready', 'quit' ]
40-
41-
// export async function isPluginSupported (plugin, target) {
42-
43-
// const isDesktopBuild = target === 'desktop'
44-
45-
// let { desktop } = plugin
46-
// if (desktop && isDesktopBuild) return true // Desktop plugins are always supported in desktop builds
47-
48-
// const supported = []
49-
// for (const feature of commonPluginFeatures) {
50-
// const supported = await isPluginFeatureSupported.call(this, plugin, feature)
51-
// supported.push(supported)
52-
// }
53-
54-
// return supported.some(supported => supported) // Support if any feature is supported
55-
// }
56-
5739
export const sanitizePluginProperties = (plugin, target) => {
5840
const copy = { ...plugin }
5941

packages/core/build.ts

Lines changed: 9 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
vite,
1515
electronVersion,
1616
} from './globals.js'
17+
import { TARGET_ELECTRON, DIR_ELECTRON, DIR_MOBILE } from './constants.js'
1718
import {
1819
BuildHooks,
1920
ServiceBuildOptions,
@@ -35,11 +36,8 @@ import merge from './utils/merge.js'
3536
// chainArtifactBuildCompleted,
3637
// debugAfterPack,
3738
// makeAfterPackEmbedAsarIntegrity,
38-
// readIntegrityResource,
39-
// afterPackFlipFuses
40-
// } from "./utils/asar/security.js";
41-
42-
// import { logAsarState } from "./utils/asar/debug.js";
39+
// ASAR security features - commented out pending future implementation
40+
// See: https://github.com/commoners/commoners/issues/XXX
4341

4442
// Core Internal Imports
4543
import { configureForDesktop, resolveConfig, resolveHooks } from './index.js'
@@ -61,8 +59,6 @@ export const buildServices = async (config: UserConfig = {}, options: ServiceBui
6159

6260
const { outDir } = options
6361

64-
// if (!dev) await printHeader(`${name} – ${buildOnlyServices ? 'Building Selected Services' : `${getTargetDisplayName(target)} Build`}`)
65-
6662
const resolvedConfig = await resolveConfig(config, { services, build: true })
6763
const { hooks } = resolvedConfig
6864

@@ -117,7 +113,7 @@ export async function buildApp(
117113

118114
const { publish, sign } = build
119115

120-
const isElectronBuild = target === 'electron'
116+
const isElectronBuild = target === TARGET_ELECTRON
121117
const isDesktopBuild = isDesktop(target)
122118
const isMobileBuild = isMobile(target)
123119

@@ -131,7 +127,7 @@ export async function buildApp(
131127

132128
let wasOverwritten = false
133129
if (customTempDir) {
134-
outDir = join(root, globalTempDir, isElectronBuild ? 'electron' : 'mobile')
130+
outDir = join(root, globalTempDir, isElectronBuild ? DIR_ELECTRON : DIR_MOBILE)
135131
const { overwrite: __wasOverwritten } = await handleTemporaryDirectories(
136132
dirname(outDir),
137133
overwrite
@@ -178,7 +174,7 @@ export async function buildApp(
178174

179175
if (onBuildAssets) {
180176
const result = onBuildAssets(outDir)
181-
if (result === null) return // Skip packaging if requested
177+
if (result === null) return undefined // Skip packaging if requested
182178
}
183179

184180
// ------------------------- Target-Specific Build Steps -------------------------
@@ -272,7 +268,7 @@ export async function buildApp(
272268
if (preferredWinIcon) buildConfig.win.icon = resolveIconPath(preferredWinIcon)
273269

274270
// Ensure proper absolute paths are provided for Electron build
275-
const electronTemplateDir = path.join(templateDir, 'electron')
271+
const electronTemplateDir = path.join(templateDir, DIR_ELECTRON)
276272

277273
buildConfig.directories.buildResources = path.join(
278274
electronTemplateDir,
@@ -297,103 +293,8 @@ export async function buildApp(
297293
buildConfig[key] = path.join(root, buildConfig[key]) // Resolve paths relative to the root
298294
}
299295

300-
// // Ensure electron-builder runs our integrity injector first, then flips fuses
301-
// if (buildConfig.asar && security.integrity) {
302-
303-
// // Create debugged hook functions
304-
// const debuggedAfterPackFlipFuses = async (context: any) => {
305-
// const asarPath = join(context.appOutDir, 'resources', 'app.asar');
306-
// logAsarState('BEFORE_FUSE_FLIP', asarPath, { hook: 'afterPackFlipFuses' });
307-
308-
// await afterPackFlipFuses(context);
309-
310-
// logAsarState('AFTER_FUSE_FLIP', asarPath, { hook: 'afterPackFlipFuses' });
311-
// };
312-
313-
// // Add this after your signing step
314-
// const verifyIntegrityAfterSigning = async (config: any, fail = true) => {
315-
// const exePath = path.resolve(config.file);
316-
317-
// // Log ASAR state during artifact build completion
318-
// const artifactDir = path.dirname(exePath);
319-
// const possibleAsarPaths = [
320-
// path.join(artifactDir, 'win-unpacked', 'resources', 'app.asar'),
321-
// path.join(path.dirname(artifactDir), 'win-unpacked', 'resources', 'app.asar'),
322-
// ];
323-
324-
// for (const asarPath of possibleAsarPaths) {
325-
// if (existsSync(asarPath)) {
326-
// logAsarState('ARTIFACT_BUILD_COMPLETED_VERIFICATION', asarPath, {
327-
// artifact: path.basename(exePath),
328-
// hook: 'verifyIntegrityAfterSigning'
329-
// });
330-
// break;
331-
// }
332-
// }
333-
334-
// const embedded = readIntegrityResource(exePath);
335-
// if (!embedded.length) {
336-
// const message = `⚠️\tNo integrity resource found in ${exePath}. This may indicate a problem with the signing process.`;
337-
// if (fail) throw new Error(message);
338-
// console.warn(message);
339-
// return;
340-
// }
341-
// };
342-
343-
// // OPTIONAL: if you still patch app.asar (e.g., your test blocker), do it here.
344-
// // Ensure it modifies the ASAR at `${appOutDir}/resources/app.asar` (Win/Linux) or
345-
// // `${appOutDir}/${product}.app/Contents/Resources/app.asar` (macOS).
346-
// const mutateAsar = async ({ appOutDir, productName }) => {
347-
// // Track ASAR state before mutation
348-
// const asarPath = join(appOutDir, 'resources', 'app.asar');
349-
// logAsarState('MUTATE_ASAR_START', asarPath, { hook: 'mutateAsar' });
350-
351-
// // Example: run your patcher here so the final hash matches what ships.
352-
// // await cp.execFile('node', ['utilities/patch-electron-asar.js', '--app', appOutDir]);
353-
// console.log('🔧 ASAR mutation step (currently no-op)');
354-
355-
// logAsarState('MUTATE_ASAR_END', asarPath, { hook: 'mutateAsar' });
356-
// };
357-
358-
// // Hook setup with comprehensive debugging
359-
// buildConfig.afterPack = chainAfterPack(
360-
// buildConfig.afterPack,
361-
// debugAfterPack,
362-
// debuggedAfterPackFlipFuses, // flip fuses first
363-
// makeAfterPackEmbedAsarIntegrity(mutateAsar) // then embed integrity LAST
364-
// );
365-
366-
// buildConfig.artifactBuildCompleted = chainArtifactBuildCompleted(
367-
// buildConfig.artifactBuildCompleted,
368-
// (config) => {
369-
// // Add comprehensive logging for artifact build completion
370-
// const exePath = path.resolve(config.file);
371-
// console.log(`\n🔍 Artifact Build Completed: ${path.basename(exePath)}`);
372-
373-
// // Find and log the associated unpacked directory
374-
// const artifactDir = path.dirname(exePath);
375-
// const possibleUnpackedDirs = [
376-
// path.join(artifactDir, 'win-unpacked'),
377-
// path.join(path.dirname(artifactDir), 'win-unpacked'),
378-
// ];
379-
380-
// for (const unpackedDir of possibleUnpackedDirs) {
381-
// if (existsSync(unpackedDir)) {
382-
// const asarPath = path.join(unpackedDir, 'resources', 'app.asar');
383-
// if (existsSync(asarPath)) {
384-
// logAsarState('ARTIFACT_BUILD_COMPLETED', asarPath, {
385-
// artifact: path.basename(exePath),
386-
// unpackedDir,
387-
// hook: 'artifactBuildCompleted'
388-
// });
389-
// }
390-
// }
391-
// }
392-
393-
// return verifyIntegrityAfterSigning(config, false);
394-
// }
395-
// );
396-
// }
296+
// TODO: Implement ASAR integrity checking
297+
// See: https://github.com/commoners/commoners/issues/XXX
397298

398299
buildConfig.mac.entitlementsInherit = path.join(
399300
electronTemplateDir,

0 commit comments

Comments
 (0)