Files
aliasvault/apps/mobile-app/utils/DeepLinkResolver.ts
dependabot[bot] 423330c864 Upgrade mobile app Expo and browser extension WXT frameworks (#2067)
* Bump the npm_and_yarn group across 2 directories with 2 updates

Bumps the npm_and_yarn group with 1 update in the /apps/browser-extension directory: [ws](https://github.com/websockets/ws).
Bumps the npm_and_yarn group with 1 update in the /apps/mobile-app directory: [postcss](https://github.com/postcss/postcss).


Updates `ws` from 8.18.2 to 8.21.0
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.18.2...8.21.0)

Updates `ws` from 8.18.2 to 8.21.0
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.18.2...8.21.0)

Updates `postcss` from 8.4.49 to 8.5.15
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.49...8.5.15)

Updates `postcss` from 8.4.49 to 8.5.15
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.49...8.5.15)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.15
  dependency-type: indirect
- dependency-name: ws
  dependency-version: 8.21.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update package-lock.json (#2067)

* Update NodeJS to latest 24.x LTS

* Revert Expo back to 53.x (#2067)

* Upgrade expo and react-native (#2067)

* Update mobile app to support Expo 56 (#2067)

* Update wxt (#2067)

* Change util filenames to be consistent PascalCase (#2067)

* Restore deep-linking behavior to work with new Expo Router (#2067)

* Update eslint.config.js (#2067)

* Update package-lock.json (#2067)

* Refactor linting (#2067)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Leendert de Borst <ldeborst@xivisoft.com>
2026-05-26 10:47:39 +02:00

146 lines
4.3 KiB
TypeScript

import NativeVaultManager from '@/specs/NativeVaultManager';
declare const __DEV__: boolean;
export type ResolvedTarget = {
path: string;
params?: Record<string, string>;
};
/**
* Resolve an `open/<action>/...` URL into a final navigation target.
*
* Returns null when the action is unrecognised or is missing required params.
* For `__debug__/...` actions the navigation target is always /(tabs)/items
* and the associated native side effect is awaited internally before the
* function resolves — E2E callers can deep-link into a debug action and
* trust that the resulting state (e.g. offline mode) is applied by the time
* navigation runs.
*
* Used by both the cold-boot interceptor (root layout) and warm-start
* ActionHandler so the action→path mapping lives in one place.
*/
export async function resolveOpenAction(
actionSegments: string[],
queryParams: Record<string, string>,
): Promise<ResolvedTarget | null> {
const [action, ...rest] = actionSegments;
switch (action) {
case 'mobile-unlock': {
const requestId = rest[0];
if (!requestId) {
return null;
}
const params: Record<string, string> = {};
if (queryParams.pk) {
params.pk = queryParams.pk;
}
return {
path: `/(tabs)/settings/mobile-unlock/${requestId}`,
params: Object.keys(params).length > 0 ? params : undefined,
};
}
case '__debug__':
if (!__DEV__) {
return null;
}
try {
await executeDebugSideEffect(rest);
} catch (err) {
console.error('[DeepLinkResolver] debug side effect failed:', err);
}
return { path: '/(tabs)/items' };
default:
return null;
}
}
/**
* Whether an `open/<action>` requires the vault to be unlocked before the
* resolved target makes sense. Warm-start ActionHandler uses this to decide
* between navigating directly and detouring through /reinitialize.
*/
export function openActionRequiresVaultUnlock(actionSegments: string[]): boolean {
return actionSegments[0] === 'mobile-unlock';
}
/**
* Parse a deep-link URL and resolve into a post-unlock navigation target.
*
* - `aliasvault://open/<action>/...` → `resolveOpenAction`
* - any other path (e.g. `aliasvault://items/abc`) → that route directly
*
* Used by the root layout's cold-boot interceptor. The caller is responsible
* for routing through /initialize before navigating to the returned target.
* Returns null for invalid, empty, or unrecognised URLs.
*/
export async function resolveDeepLink(url: string | null): Promise<ResolvedTarget | null> {
if (!url) {
return null;
}
let rawPath = '';
const queryParams: Record<string, string> = {};
try {
const parsed = new URL(url);
rawPath = `${parsed.host}${parsed.pathname}`.replace(/^\/+/, '');
parsed.searchParams.forEach((value, key) => {
queryParams[key] = value;
});
} catch {
return null;
}
if (!rawPath) {
return null;
}
const segments = rawPath.split('/').filter(Boolean);
if (segments[0] === 'open') {
return resolveOpenAction(segments.slice(1), queryParams);
}
return {
path: rawPath,
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
};
}
/**
* Execute the side effect for a `__debug__/<debugAction>` URL.
*
* `debugSegments` is the path segments AFTER `__debug__/`, e.g. for
* `__debug__/set-offline/true` this receives `['set-offline', 'true']`.
*/
async function executeDebugSideEffect(debugSegments: string[]): Promise<void> {
if (!__DEV__) {
return;
}
const [debugAction, ...debugParams] = debugSegments;
switch (debugAction) {
case 'set-offline': {
const isOffline = debugParams[0] === 'true';
console.debug('[DeepLinkResolver] Setting offline mode:', isOffline);
await NativeVaultManager.setOfflineMode(isOffline);
return;
}
case 'set-api-url': {
if (debugParams.length === 0) {
console.error('[DeepLinkResolver] set-api-url requires URL parameter');
return;
}
// Join all remaining segments so unencoded slashes in the URL still work.
const url = decodeURIComponent(debugParams.join('/'));
console.debug('[DeepLinkResolver] Setting API URL:', url);
await NativeVaultManager.setApiUrl(url);
return;
}
default:
console.warn('[DeepLinkResolver] Unknown debug action:', debugAction);
}
}