@calo-design/cli 0.9.2 → 0.9.3
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/bin/mirror-push.js +65 -17
- package/package.json +1 -1
package/bin/mirror-push.js
CHANGED
|
@@ -382,7 +382,7 @@ export default function RootLayout() {
|
|
|
382
382
|
}
|
|
383
383
|
fs.writeFileSync(path.join(stagedAppDir, "_layout.tsx"), managed);
|
|
384
384
|
fs.writeFileSync(path.join(mirrorChromeDir, "mirror-chrome.tsx"), mirrorChromeSource({ slug, owner }));
|
|
385
|
-
injectNativeIntent(stagedAppDir);
|
|
385
|
+
injectNativeIntent(stagedAppDir, slug);
|
|
386
386
|
}
|
|
387
387
|
|
|
388
388
|
// The launcher opens a prototype via `designchef://open/<slug>`. That deep link is
|
|
@@ -394,35 +394,83 @@ export default function RootLayout() {
|
|
|
394
394
|
// `+native-intent.tsx` is expo-router's hook for rewriting an incoming native URL
|
|
395
395
|
// before routing: send the launcher's own path to the root and leave every other
|
|
396
396
|
// deep link untouched, so a prototype's own links keep working.
|
|
397
|
-
function injectNativeIntent(stagedAppDir) {
|
|
397
|
+
function injectNativeIntent(stagedAppDir, slug) {
|
|
398
398
|
const existing = [".tsx", ".ts", ".jsx", ".js"].find((e) =>
|
|
399
399
|
fs.existsSync(path.join(stagedAppDir, "+native-intent" + e))
|
|
400
400
|
);
|
|
401
401
|
if (existing) {
|
|
402
|
-
warn("this prototype has its own +native-intent — leaving it alone.
|
|
402
|
+
warn("this prototype has its own +native-intent — leaving it alone. Launcher URLs (/open/<slug>) won't be handled: route them to \"/\" for this prototype's slug and switch expo-updates channels for other slugs.");
|
|
403
403
|
return;
|
|
404
404
|
}
|
|
405
405
|
fs.writeFileSync(
|
|
406
406
|
path.join(stagedAppDir, "+native-intent.tsx"),
|
|
407
407
|
`// Managed by calo-design push.
|
|
408
|
-
// The Mirror launcher opens
|
|
409
|
-
//
|
|
410
|
-
//
|
|
411
|
-
|
|
408
|
+
// The Mirror launcher opens prototypes with designchef://open/<slug>. Two cases
|
|
409
|
+
// reach THIS bundle:
|
|
410
|
+
// - the URL that opened this prototype survives the expo-updates reload as the
|
|
411
|
+
// initial URL (/open/<own slug>) — route it to "/" so expo-router doesn't
|
|
412
|
+
// render "Unmatched Route";
|
|
413
|
+
// - a designchef://open/<other> link arrives while this bundle is live — the
|
|
414
|
+
// launcher's JS isn't running, so this bundle performs the channel switch
|
|
415
|
+
// itself: point expo-updates at the other channel, download, reload.
|
|
416
|
+
// ("mirror" is the launcher's own channel, so open/mirror = back to the feed.)
|
|
417
|
+
import { Platform } from "react-native";
|
|
418
|
+
import * as Updates from "expo-updates";
|
|
412
419
|
|
|
413
|
-
|
|
420
|
+
const PROTOTYPE = ${JSON.stringify(slug)};
|
|
421
|
+
const UPDATES_URL = ${JSON.stringify(UPDATES_URL)};
|
|
422
|
+
const RUNTIME_VERSION = ${JSON.stringify(RUNTIME_VERSION)};
|
|
423
|
+
|
|
424
|
+
// One switch at a time — a second reload racing the first crashes in JSI teardown
|
|
425
|
+
// (see calo-design-mirror src/lib/mirror.ts). Reset on failure so retry works.
|
|
426
|
+
let switching = false;
|
|
427
|
+
function switchToChannel(channel: string): void {
|
|
428
|
+
if (switching) return;
|
|
429
|
+
let enabled = false;
|
|
430
|
+
try { enabled = Updates.isEnabled; } catch {}
|
|
431
|
+
if (!enabled) return; // dev/Expo Go — no runtime loading there
|
|
432
|
+
switching = true;
|
|
433
|
+
(async () => {
|
|
434
|
+
await Updates.setUpdateURLAndRequestHeadersOverride({
|
|
435
|
+
updateUrl: UPDATES_URL,
|
|
436
|
+
// EAS requires all three headers — channel alone is an HTTP 400.
|
|
437
|
+
requestHeaders: {
|
|
438
|
+
"expo-channel-name": channel,
|
|
439
|
+
"expo-runtime-version": Updates.runtimeVersion ?? RUNTIME_VERSION,
|
|
440
|
+
"expo-platform": Platform.OS,
|
|
441
|
+
},
|
|
442
|
+
});
|
|
443
|
+
// Download BEFORE reloading; if the channel has nothing this throws and we
|
|
444
|
+
// stay put instead of reloading into nothing.
|
|
445
|
+
await Updates.fetchUpdateAsync();
|
|
446
|
+
// Defer the reload off the awaited chain (JSI teardown race — see mirror.ts).
|
|
447
|
+
setTimeout(() => { void Updates.reloadAsync().catch(() => { switching = false; }); }, 300);
|
|
448
|
+
})().catch(() => { switching = false; });
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// "/open/<slug>", "scheme://open/<slug>" (host parses as "open"), and
|
|
452
|
+
// "scheme:///open/<slug>" all mean the launcher; anything else is the
|
|
453
|
+
// prototype's own link. Returns the slug ("" for a bare /open), or null.
|
|
454
|
+
function launcherSlug(path: string): string | null {
|
|
414
455
|
try {
|
|
415
|
-
|
|
416
|
-
if (path.startsWith("/"))
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
456
|
+
let pathname: string;
|
|
457
|
+
if (path.startsWith("/")) pathname = path;
|
|
458
|
+
else {
|
|
459
|
+
const url = new URL(path);
|
|
460
|
+
pathname = url.host === "open" ? "/open" + url.pathname : url.pathname;
|
|
461
|
+
}
|
|
462
|
+
const m = pathname.match(/^\\/open(?:\\/([^/?#]*))?(?:[/?#]|$)/);
|
|
463
|
+
return m ? decodeURIComponent(m[1] ?? "") : null;
|
|
422
464
|
} catch {
|
|
423
|
-
|
|
465
|
+
return null;
|
|
424
466
|
}
|
|
425
|
-
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export function redirectSystemPath({ path }: { path: string; initial: boolean }): string {
|
|
470
|
+
const slug = launcherSlug(path);
|
|
471
|
+
if (slug === null) return path; // not a launcher URL — leave this prototype's own links alone
|
|
472
|
+
if (slug && slug !== PROTOTYPE) switchToChannel(slug);
|
|
473
|
+
return "/";
|
|
426
474
|
}
|
|
427
475
|
`
|
|
428
476
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@calo-design/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "One-line setup for Calo design tooling: logs in with your Calo email and installs the calo-design skill + design-system packages. No GitHub account needed.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"calo-design": "bin/cli.js"
|