fix(shared): drop .js extensions from relative imports for Metro

packages/shared/src/index.ts and all sub-modules used .js extensions on
relative imports (e.g. './admin/index.js') pointing at .ts source files.
TypeScript with moduleResolution: "Bundler" doesn't need them, and
Metro's eager exporter (used for preview / production builds) reads
them literally and fails — only the dev-server Metro fell back to .ts.

Workspace typecheck remains 8/8 green; Vite and TS Bundler resolution
already accept both styles, so desktop is unaffected.
This commit is contained in:
byGalax
2026-05-15 01:52:14 +02:00
parent b0967dd2c5
commit b61f929cf7
25 changed files with 108 additions and 108 deletions
+9 -9
View File
@@ -1,8 +1,8 @@
import { fromBase64, generateX25519KeyPair, toBase64, wipe } from '../crypto/index.js';
import { bytesToPgHex, pgHexToBytes } from '../supabase/bytea.js';
import type { AppSupabaseClient } from '../supabase/client.js';
import type { DevicePlatform } from '../supabase/types.js';
import type { SecretStore } from './secure-storage.js';
import { fromBase64, generateX25519KeyPair, toBase64, wipe } from '../crypto/index';
import { bytesToPgHex, pgHexToBytes } from '../supabase/bytea';
import type { AppSupabaseClient } from '../supabase/client';
import type { DevicePlatform } from '../supabase/types';
import type { SecretStore } from './secure-storage';
export interface RegisterDeviceParams {
name: string; // user-facing, e.g. "Dennis Laptop"
@@ -153,7 +153,7 @@ export async function saveDevicePrivateKey(
}
// Restores a device record from a backup by re-seeding the local private key
// store for an EXISTING server-side device row. Does NOT insert a new row
// store for an EXISTING server-side device row. Does NOT insert a new row —
// the original row is kept intact so conversation-key bundles stay valid.
// Throws when the server-side device was removed (the backup is then unusable;
// user must provision a fresh device and get conv-keys shared from another
@@ -169,7 +169,7 @@ export async function restoreDeviceFromServerRecord(params: {
if (!session.user) throw new Error('not authenticated');
if (session.user.id !== params.userId) {
throw new Error(
'Backup is for a different account sign in as the owner before restoring.',
'Backup is for a different account — sign in as the owner before restoring.',
);
}
@@ -182,7 +182,7 @@ export async function restoreDeviceFromServerRecord(params: {
if (error) throw error;
if (!row) {
throw new Error(
'Device record not found on server it was removed. Backup is no longer valid; register a new device instead.',
'Device record not found on server — it was removed. Backup is no longer valid; register a new device instead.',
);
}
@@ -211,5 +211,5 @@ export function deviceIdStorageKey(userId: string): string {
}
// Intentional re-exports so app layers only need @chat-app/shared/auth.
export type { SecretStore } from './secure-storage.js';
export type { SecretStore } from './secure-storage';
export { toBase64 as base64FromBytes, fromBase64 as bytesFromBase64 };
+3 -3
View File
@@ -1,3 +1,3 @@
export * from './device.js';
export * from './magic-link.js';
export * from './profile.js';
export * from './device';
export * from './magic-link';
export * from './profile';
+5 -5
View File
@@ -1,5 +1,5 @@
import type { SupportedLocale } from '../i18n/types.js';
import type { AppSupabaseClient } from '../supabase/client.js';
import type { SupportedLocale } from '../i18n/types';
import type { AppSupabaseClient } from '../supabase/client';
export interface SignupParams {
email: string;
@@ -58,7 +58,7 @@ export async function loginWithMagicLink(
}
// Parse a callback URL produced by the magic-link email and establish a session.
// Works for both PKCE (`?code=`) and legacy token-hash (`#access_token=`).
// Works for both PKCE (`?code=…`) and legacy token-hash (`#access_token=…`).
export async function completeSessionFromUrl(
client: AppSupabaseClient,
url: string,
@@ -91,14 +91,14 @@ export async function completeSessionFromUrl(
export async function signOut(client: AppSupabaseClient): Promise<void> {
// `scope: 'local'` only ends the session in THIS client. Without it Supabase
// defaults to 'global', which invalidates the user's refresh tokens
// everywhere meaning a logout in the browser would also kick the desktop
// everywhere — meaning a logout in the browser would also kick the desktop
// app (and vice versa) the next time it tries to refresh its token.
const { error } = await client.auth.signOut({ scope: 'local' });
if (error) throw error;
}
// Verify a 6-digit OTP that arrived via magic-link email. Establishes a
// session in the CURRENT webview no browser redirect involved. Used by the
// session in the CURRENT webview — no browser redirect involved. Used by the
// desktop/mobile apps where cross-origin redirects don't carry the session
// back to the native webview.
export async function verifyMagicLinkOtp(
+5 -5
View File
@@ -1,6 +1,6 @@
import type { SupportedLocale } from '../i18n/types.js';
import type { AppSupabaseClient } from '../supabase/client.js';
import type { Database, PresenceState } from '../supabase/types.js';
import type { SupportedLocale } from '../i18n/types';
import type { AppSupabaseClient } from '../supabase/client';
import type { Database, PresenceState } from '../supabase/types';
type ProfileUpdate = Database['public']['Tables']['profiles']['Update'];
@@ -75,7 +75,7 @@ export async function getProfileByUsername(
const { data, error } = await client
.from('profiles')
.select(PROFILE_COLS)
// citext column compares CI server-side send raw input, don't force case.
// citext column compares CI server-side — send raw input, don't force case.
.eq('username', username.trim())
.maybeSingle();
if (error) throw error;
@@ -89,7 +89,7 @@ export async function isUsernameAvailable(
const { count, error } = await client
.from('profiles')
.select('user_id', { count: 'exact', head: true })
// citext compares CI no manual normalization needed.
// citext compares CI — no manual normalization needed.
.eq('username', username.trim());
if (error) throw error;
return (count ?? 0) === 0;