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:
@@ -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 };
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user