pake-cli 3.11.10 โ 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +82 -26
- package/package.json +1 -1
- package/src-tauri/Cargo.lock +1 -1
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/src/inject/auth.js +20 -6
- package/src-tauri/src/inject/event.js +24 -5
- package/src-tauri/tauri.conf.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -20,7 +20,7 @@ import { InvalidArgumentError, program as program$1, Option } from 'commander';
|
|
|
20
20
|
import fs$1 from 'fs';
|
|
21
21
|
|
|
22
22
|
var name = "pake-cli";
|
|
23
|
-
var version = "3.
|
|
23
|
+
var version = "3.12.0";
|
|
24
24
|
var description = "๐คฑ๐ป Turn any webpage into a desktop app with one command. ๐คฑ๐ป ไธ้ฎๆๅ
็ฝ้กต็ๆ่ฝป้ๆก้ขๅบ็จใ";
|
|
25
25
|
var engines = {
|
|
26
26
|
node: ">=18.0.0"
|
|
@@ -431,13 +431,14 @@ function needsTemporaryDebForZst(targets) {
|
|
|
431
431
|
*/
|
|
432
432
|
function buildWindowConfigOverrides(options, platform = asSupportedPlatform(process.platform)) {
|
|
433
433
|
const platformHideOnClose = options.hideOnClose ?? platform === 'darwin';
|
|
434
|
+
const platformHideTitleBar = platform === 'darwin' ? options.hideTitleBar : false;
|
|
434
435
|
return {
|
|
435
436
|
width: options.width,
|
|
436
437
|
height: options.height,
|
|
437
438
|
fullscreen: options.fullscreen,
|
|
438
439
|
maximize: options.maximize,
|
|
439
440
|
resizable: options.resizable ?? true,
|
|
440
|
-
hide_title_bar:
|
|
441
|
+
hide_title_bar: platformHideTitleBar,
|
|
441
442
|
activation_shortcut: options.activationShortcut,
|
|
442
443
|
always_on_top: options.alwaysOnTop,
|
|
443
444
|
dark_mode: options.darkMode,
|
|
@@ -712,6 +713,9 @@ async function mergeConfig(url, options, tauriConf) {
|
|
|
712
713
|
await copyTemplateConfigs();
|
|
713
714
|
const { appVersion, userAgent, showSystemTray, useLocalFile, identifier, name = 'pake-app', installerLanguage, wasm, camera, microphone, } = options;
|
|
714
715
|
const platform = asSupportedPlatform(process.platform);
|
|
716
|
+
if (options.hideTitleBar && platform !== 'darwin') {
|
|
717
|
+
logger.warn('โผ --hide-title-bar is only supported on macOS and will be ignored on this platform.');
|
|
718
|
+
}
|
|
715
719
|
const tauriConfWindowOptions = buildWindowConfigOverrides(options, platform);
|
|
716
720
|
Object.assign(tauriConf.pake.windows[0], { url, ...tauriConfWindowOptions });
|
|
717
721
|
tauriConf.productName = name;
|
|
@@ -1162,14 +1166,22 @@ class BaseBuilder {
|
|
|
1162
1166
|
return 0; // Disable proxy feature if version detection fails
|
|
1163
1167
|
}
|
|
1164
1168
|
}
|
|
1169
|
+
getCargoTargetDir() {
|
|
1170
|
+
return process.env.CARGO_TARGET_DIR || path.join('src-tauri', 'target');
|
|
1171
|
+
}
|
|
1172
|
+
resolveBuildPath(npmDirectory, buildPath) {
|
|
1173
|
+
return path.isAbsolute(buildPath)
|
|
1174
|
+
? buildPath
|
|
1175
|
+
: path.join(npmDirectory, buildPath);
|
|
1176
|
+
}
|
|
1165
1177
|
getBasePath() {
|
|
1166
1178
|
const basePath = this.options.debug ? 'debug' : 'release';
|
|
1167
|
-
return
|
|
1179
|
+
return path.join(this.getCargoTargetDir(), basePath, 'bundle');
|
|
1168
1180
|
}
|
|
1169
1181
|
getBuildAppPath(npmDirectory, fileName, fileType) {
|
|
1170
1182
|
// For app bundles on macOS, the directory is 'macos', not 'app'
|
|
1171
1183
|
const bundleDir = fileType.toLowerCase() === 'app' ? 'macos' : fileType.toLowerCase();
|
|
1172
|
-
return path.join(npmDirectory, this.getBasePath(), bundleDir, `${fileName}.${fileType}`);
|
|
1184
|
+
return path.join(this.resolveBuildPath(npmDirectory, this.getBasePath()), bundleDir, `${fileName}.${fileType}`);
|
|
1173
1185
|
}
|
|
1174
1186
|
/**
|
|
1175
1187
|
* Copy raw binary file to output directory
|
|
@@ -1196,9 +1208,9 @@ class BaseBuilder {
|
|
|
1196
1208
|
const binaryName = this.getBinaryName(appName);
|
|
1197
1209
|
// Handle cross-platform builds
|
|
1198
1210
|
if (this.options.multiArch || this.hasArchSpecificTarget()) {
|
|
1199
|
-
return path.join(npmDirectory, this.getArchSpecificPath(), basePath, binaryName);
|
|
1211
|
+
return path.join(this.resolveBuildPath(npmDirectory, this.getArchSpecificPath()), basePath, binaryName);
|
|
1200
1212
|
}
|
|
1201
|
-
return path.join(npmDirectory,
|
|
1213
|
+
return path.join(this.resolveBuildPath(npmDirectory, this.getCargoTargetDir()), basePath, binaryName);
|
|
1202
1214
|
}
|
|
1203
1215
|
/**
|
|
1204
1216
|
* Get the output path for the raw binary file
|
|
@@ -1229,7 +1241,7 @@ class BaseBuilder {
|
|
|
1229
1241
|
* Get architecture-specific path for binary
|
|
1230
1242
|
*/
|
|
1231
1243
|
getArchSpecificPath() {
|
|
1232
|
-
return
|
|
1244
|
+
return this.getCargoTargetDir(); // Override in subclasses if needed
|
|
1233
1245
|
}
|
|
1234
1246
|
}
|
|
1235
1247
|
BaseBuilder.ARCH_MAPPINGS = {
|
|
@@ -1315,7 +1327,10 @@ class MacBuilder extends BaseBuilder {
|
|
|
1315
1327
|
const basePath = this.options.debug ? 'debug' : 'release';
|
|
1316
1328
|
const actualArch = this.getActualArch();
|
|
1317
1329
|
const target = this.getTauriTarget(actualArch, 'darwin');
|
|
1318
|
-
|
|
1330
|
+
if (!target) {
|
|
1331
|
+
throw new Error(`Unsupported architecture: ${actualArch} for macOS`);
|
|
1332
|
+
}
|
|
1333
|
+
return path.join(this.getCargoTargetDir(), target, basePath, 'bundle');
|
|
1319
1334
|
}
|
|
1320
1335
|
hasArchSpecificTarget() {
|
|
1321
1336
|
return true;
|
|
@@ -1323,7 +1338,10 @@ class MacBuilder extends BaseBuilder {
|
|
|
1323
1338
|
getArchSpecificPath() {
|
|
1324
1339
|
const actualArch = this.getActualArch();
|
|
1325
1340
|
const target = this.getTauriTarget(actualArch, 'darwin');
|
|
1326
|
-
|
|
1341
|
+
if (!target) {
|
|
1342
|
+
throw new Error(`Unsupported architecture: ${actualArch} for macOS`);
|
|
1343
|
+
}
|
|
1344
|
+
return path.join(this.getCargoTargetDir(), target);
|
|
1327
1345
|
}
|
|
1328
1346
|
}
|
|
1329
1347
|
|
|
@@ -1354,14 +1372,26 @@ class WinBuilder extends BaseBuilder {
|
|
|
1354
1372
|
getBasePath() {
|
|
1355
1373
|
const basePath = this.options.debug ? 'debug' : 'release';
|
|
1356
1374
|
const target = this.getTauriTarget(this.buildArch, 'win32');
|
|
1357
|
-
|
|
1375
|
+
if (!target) {
|
|
1376
|
+
throw new Error(`Unsupported architecture: ${this.buildArch} for Windows`);
|
|
1377
|
+
}
|
|
1378
|
+
return path.join(this.getCargoTargetDir(), target, basePath, 'bundle');
|
|
1358
1379
|
}
|
|
1359
1380
|
hasArchSpecificTarget() {
|
|
1360
1381
|
return true;
|
|
1361
1382
|
}
|
|
1362
1383
|
getArchSpecificPath() {
|
|
1363
1384
|
const target = this.getTauriTarget(this.buildArch, 'win32');
|
|
1364
|
-
|
|
1385
|
+
if (!target) {
|
|
1386
|
+
throw new Error(`Unsupported architecture: ${this.buildArch} for Windows`);
|
|
1387
|
+
}
|
|
1388
|
+
return path.join(this.getCargoTargetDir(), target);
|
|
1389
|
+
}
|
|
1390
|
+
getRawBinaryPath(appName) {
|
|
1391
|
+
return `${appName}.exe`;
|
|
1392
|
+
}
|
|
1393
|
+
getBinaryName(appName) {
|
|
1394
|
+
return `pake-${generateIdentifierSafeName(appName)}.exe`;
|
|
1365
1395
|
}
|
|
1366
1396
|
}
|
|
1367
1397
|
|
|
@@ -1556,7 +1586,10 @@ post_remove() {
|
|
|
1556
1586
|
const basePath = this.options.debug ? 'debug' : 'release';
|
|
1557
1587
|
if (this.buildArch === 'arm64') {
|
|
1558
1588
|
const target = this.getTauriTarget(this.buildArch, 'linux');
|
|
1559
|
-
|
|
1589
|
+
if (!target) {
|
|
1590
|
+
throw new Error(`Unsupported architecture: ${this.buildArch} for Linux`);
|
|
1591
|
+
}
|
|
1592
|
+
return path.join(this.getCargoTargetDir(), target, basePath, 'bundle');
|
|
1560
1593
|
}
|
|
1561
1594
|
return super.getBasePath();
|
|
1562
1595
|
}
|
|
@@ -1572,7 +1605,10 @@ post_remove() {
|
|
|
1572
1605
|
getArchSpecificPath() {
|
|
1573
1606
|
if (this.buildArch === 'arm64') {
|
|
1574
1607
|
const target = this.getTauriTarget(this.buildArch, 'linux');
|
|
1575
|
-
|
|
1608
|
+
if (!target) {
|
|
1609
|
+
throw new Error(`Unsupported architecture: ${this.buildArch} for Linux`);
|
|
1610
|
+
}
|
|
1611
|
+
return path.join(this.getCargoTargetDir(), target);
|
|
1576
1612
|
}
|
|
1577
1613
|
return super.getArchSpecificPath();
|
|
1578
1614
|
}
|
|
@@ -2410,6 +2446,20 @@ function normalizeUrl(urlToNormalize) {
|
|
|
2410
2446
|
throw new Error(`Your url "${urlWithProtocol}" is invalid: ${err.message}`);
|
|
2411
2447
|
}
|
|
2412
2448
|
}
|
|
2449
|
+
// Compiles a comma-separated domain list into a regex source for
|
|
2450
|
+
// internal_url_regex. Each domain is escaped and matched against the URL host
|
|
2451
|
+
// and its subdomains so path or query text cannot accidentally opt a link in.
|
|
2452
|
+
// Returns '' for empty input.
|
|
2453
|
+
function safeDomainsToRegex(domains) {
|
|
2454
|
+
const escaped = domains
|
|
2455
|
+
.split(',')
|
|
2456
|
+
.map((domain) => domain.trim().toLowerCase())
|
|
2457
|
+
.filter(Boolean)
|
|
2458
|
+
.map((domain) => domain.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
2459
|
+
return escaped.length
|
|
2460
|
+
? `^https?:\\/\\/(?:[^/?#@]+\\.)*(?:${escaped.join('|')})(?::\\d+)?(?:[/?#]|$)`
|
|
2461
|
+
: '';
|
|
2462
|
+
}
|
|
2413
2463
|
|
|
2414
2464
|
/**
|
|
2415
2465
|
* Error class used for user-facing CLI errors.
|
|
@@ -2490,6 +2540,10 @@ async function handleOptions(options, url) {
|
|
|
2490
2540
|
name: resolvedName,
|
|
2491
2541
|
identifier: resolveIdentifier(url, options.name, options.identifier),
|
|
2492
2542
|
};
|
|
2543
|
+
// --safe-domain is sugar over --internal-url-regex; an explicit regex wins.
|
|
2544
|
+
if (!options.internalUrlRegex && options.safeDomain) {
|
|
2545
|
+
appOptions.internalUrlRegex = safeDomainsToRegex(options.safeDomain);
|
|
2546
|
+
}
|
|
2493
2547
|
const iconPath = await handleIcon(appOptions, url);
|
|
2494
2548
|
appOptions.icon = iconPath || '';
|
|
2495
2549
|
return appOptions;
|
|
@@ -2538,6 +2592,7 @@ const DEFAULT_PAKE_OPTIONS = {
|
|
|
2538
2592
|
startToTray: false,
|
|
2539
2593
|
forceInternalNavigation: false,
|
|
2540
2594
|
internalUrlRegex: '',
|
|
2595
|
+
safeDomain: '',
|
|
2541
2596
|
enableFind: false,
|
|
2542
2597
|
iterativeBuild: false,
|
|
2543
2598
|
zoom: 100,
|
|
@@ -2590,6 +2645,7 @@ ${green('|_| \\__,_|_|\\_\\___| can turn any webpage into a desktop app with
|
|
|
2590
2645
|
return program$1
|
|
2591
2646
|
.addHelpText('beforeAll', logo)
|
|
2592
2647
|
.usage(`[url] [options]`)
|
|
2648
|
+
.helpOption('-h, --help', 'Show all CLI options')
|
|
2593
2649
|
.showHelpAfterError()
|
|
2594
2650
|
.argument('[url]', 'The web URL you want to package', validateUrlInput)
|
|
2595
2651
|
.option('--name <string>', 'Application name')
|
|
@@ -2678,12 +2734,9 @@ ${green('|_| \\__,_|_|\\_\\___| can turn any webpage into a desktop app with
|
|
|
2678
2734
|
.addOption(new Option('--start-to-tray', 'Start app minimized to tray')
|
|
2679
2735
|
.default(DEFAULT_PAKE_OPTIONS.startToTray)
|
|
2680
2736
|
.hideHelp())
|
|
2681
|
-
.addOption(new Option('--force-internal-navigation', 'Keep every link inside the Pake window instead of opening external handlers')
|
|
2682
|
-
.default(DEFAULT_PAKE_OPTIONS.
|
|
2683
|
-
.
|
|
2684
|
-
.addOption(new Option('--internal-url-regex <string>', 'Regex pattern to match URLs that should be considered internal')
|
|
2685
|
-
.default(DEFAULT_PAKE_OPTIONS.internalUrlRegex)
|
|
2686
|
-
.hideHelp())
|
|
2737
|
+
.addOption(new Option('--force-internal-navigation', 'Keep every link inside the Pake window instead of opening external handlers').default(DEFAULT_PAKE_OPTIONS.forceInternalNavigation))
|
|
2738
|
+
.addOption(new Option('--internal-url-regex <string>', 'Regex pattern to match URLs that should be considered internal').default(DEFAULT_PAKE_OPTIONS.internalUrlRegex))
|
|
2739
|
+
.addOption(new Option('--safe-domain <domains>', 'Comma-separated domains kept inside the app (e.g. SSO/workspace callbacks)').default(DEFAULT_PAKE_OPTIONS.safeDomain))
|
|
2687
2740
|
.addOption(new Option('--enable-find', 'Enable in-page Find UI with Cmd/Ctrl+F/G shortcuts')
|
|
2688
2741
|
.default(DEFAULT_PAKE_OPTIONS.enableFind)
|
|
2689
2742
|
.hideHelp())
|
|
@@ -2714,9 +2767,7 @@ ${green('|_| \\__,_|_|\\_\\___| can turn any webpage into a desktop app with
|
|
|
2714
2767
|
.addOption(new Option('--iterative-build', 'Turn on rapid build mode (app only, no dmg/deb/msi), good for debugging')
|
|
2715
2768
|
.default(DEFAULT_PAKE_OPTIONS.iterativeBuild)
|
|
2716
2769
|
.hideHelp())
|
|
2717
|
-
.addOption(new Option('--new-window', 'Allow sites to open new windows (for auth flows, tabs, branches)')
|
|
2718
|
-
.default(DEFAULT_PAKE_OPTIONS.newWindow)
|
|
2719
|
-
.hideHelp())
|
|
2770
|
+
.addOption(new Option('--new-window', 'Allow sites to open new windows (for auth flows, tabs, branches)').default(DEFAULT_PAKE_OPTIONS.newWindow))
|
|
2720
2771
|
.addOption(new Option('--install', 'Auto-install app to /Applications (macOS) after build and remove local bundle')
|
|
2721
2772
|
.default(DEFAULT_PAKE_OPTIONS.install)
|
|
2722
2773
|
.hideHelp())
|
|
@@ -2729,14 +2780,19 @@ ${green('|_| \\__,_|_|\\_\\___| can turn any webpage into a desktop app with
|
|
|
2729
2780
|
.version(packageJson.version, '-v, --version')
|
|
2730
2781
|
.configureHelp({
|
|
2731
2782
|
sortSubcommands: true,
|
|
2783
|
+
visibleOptions: (command) => {
|
|
2784
|
+
const options = [...command.options];
|
|
2785
|
+
const helpOption = command
|
|
2786
|
+
._helpOption;
|
|
2787
|
+
if (helpOption) {
|
|
2788
|
+
options.push(helpOption);
|
|
2789
|
+
}
|
|
2790
|
+
return options;
|
|
2791
|
+
},
|
|
2732
2792
|
optionTerm: (option) => {
|
|
2733
|
-
if (option.flags === '-v, --version' || option.flags === '-h, --help')
|
|
2734
|
-
return '';
|
|
2735
2793
|
return option.flags;
|
|
2736
2794
|
},
|
|
2737
2795
|
optionDescription: (option) => {
|
|
2738
|
-
if (option.flags === '-v, --version' || option.flags === '-h, --help')
|
|
2739
|
-
return '';
|
|
2740
2796
|
return option.description;
|
|
2741
2797
|
},
|
|
2742
2798
|
});
|
package/package.json
CHANGED
package/src-tauri/Cargo.lock
CHANGED
package/src-tauri/Cargo.toml
CHANGED
|
@@ -27,12 +27,26 @@ function matchesAuthUrl(url, baseUrl = window.location.href) {
|
|
|
27
27
|
/\/o\/oauth2/,
|
|
28
28
|
];
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
// Enterprise SSO. Match identity providers on the host, and SAML/SSO/ADFS on
|
|
31
|
+
// the pathname with endpoint-shaped patterns only, so ordinary pages such as
|
|
32
|
+
// /settings/sso/providers (or a query string carrying an SSO URL) are not
|
|
33
|
+
// misread as authentication.
|
|
34
|
+
const enterpriseHostPatterns = [/(^|\.)okta\.com$/, /(^|\.)onelogin\.com$/];
|
|
35
|
+
const enterprisePathPatterns = [
|
|
36
|
+
/\/saml2?\/(sso|acs|login|metadata|consume|redirect|callback|continue)/,
|
|
37
|
+
/\/sso\/(saml|oidc|oauth|login|authorize|redirect|callback|acs|start|continue|metadata)/,
|
|
38
|
+
/\/adfs\/ls\b/,
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const isMatch =
|
|
42
|
+
oauthPatterns.some(
|
|
43
|
+
(pattern) =>
|
|
44
|
+
pattern.test(hostname) ||
|
|
45
|
+
pattern.test(pathname) ||
|
|
46
|
+
pattern.test(fullUrl),
|
|
47
|
+
) ||
|
|
48
|
+
enterpriseHostPatterns.some((pattern) => pattern.test(hostname)) ||
|
|
49
|
+
enterprisePathPatterns.some((pattern) => pattern.test(pathname));
|
|
36
50
|
|
|
37
51
|
if (isMatch) {
|
|
38
52
|
console.log("[Pake] OAuth URL detected:", url);
|
|
@@ -459,20 +459,23 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
459
459
|
const absoluteUrl = hrefUrl.href;
|
|
460
460
|
let filename = anchorElement.download || getFilenameFromUrl(absoluteUrl);
|
|
461
461
|
|
|
462
|
-
// Keep OAuth/authentication flows inside the app
|
|
462
|
+
// Keep OAuth/authentication flows inside the app. Without --new-window,
|
|
463
|
+
// navigate in place so the SSO redirect chain and callback stay in the
|
|
464
|
+
// webview instead of falling through to the system browser.
|
|
463
465
|
if (window.isAuthLink(absoluteUrl)) {
|
|
464
466
|
console.log("[Pake] Handling OAuth navigation in-app:", absoluteUrl);
|
|
467
|
+
e.preventDefault();
|
|
468
|
+
e.stopImmediatePropagation();
|
|
465
469
|
|
|
466
470
|
if (window.pakeConfig?.new_window) {
|
|
467
|
-
e.preventDefault();
|
|
468
|
-
e.stopImmediatePropagation();
|
|
469
|
-
|
|
470
471
|
openAuthNavigation(
|
|
471
472
|
originalWindowOpen,
|
|
472
473
|
absoluteUrl,
|
|
473
474
|
"_blank",
|
|
474
475
|
"width=1200,height=800,scrollbars=yes,resizable=yes",
|
|
475
476
|
);
|
|
477
|
+
} else {
|
|
478
|
+
window.location.href = absoluteUrl;
|
|
476
479
|
}
|
|
477
480
|
|
|
478
481
|
return;
|
|
@@ -488,7 +491,15 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
488
491
|
}
|
|
489
492
|
|
|
490
493
|
if (isInternalUrl(absoluteUrl)) {
|
|
491
|
-
//
|
|
494
|
+
// With --new-window the Rust on_new_window handler opens an in-app
|
|
495
|
+
// window; without it, deferring to the native handler sends the
|
|
496
|
+
// _blank target to the system browser and strands SSO callbacks.
|
|
497
|
+
// Navigate in place so internal links stay inside the webview.
|
|
498
|
+
if (!window.pakeConfig?.new_window) {
|
|
499
|
+
e.preventDefault();
|
|
500
|
+
e.stopImmediatePropagation();
|
|
501
|
+
window.location.href = absoluteUrl;
|
|
502
|
+
}
|
|
492
503
|
return;
|
|
493
504
|
}
|
|
494
505
|
|
|
@@ -592,6 +603,14 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
592
603
|
return null;
|
|
593
604
|
}
|
|
594
605
|
|
|
606
|
+
// With --new-window the native handler opens an in-app window; without it,
|
|
607
|
+
// originalWindowOpen would route the internal target to the system browser
|
|
608
|
+
// and strand SSO callbacks, so navigate in place instead.
|
|
609
|
+
if (!window.pakeConfig?.new_window) {
|
|
610
|
+
window.location.href = absoluteUrl;
|
|
611
|
+
return window;
|
|
612
|
+
}
|
|
613
|
+
|
|
595
614
|
return originalWindowOpen.call(window, absoluteUrl, name, specs);
|
|
596
615
|
} catch (error) {
|
|
597
616
|
return originalWindowOpen.call(window, url, name, specs);
|