Insole-production time tracker exported from the Create/Anything AI platform. Baseline snapshot before any reverse-engineering or cleanup. - apps/mobile: Expo Router app (iOS/Android/web), the only workspace - publisher/: standalone OpenNext/AWS deploy tooling for the web side - Backend (/api/tasks, /api/logs + DB) lives remotely, not in this repo
80 lines
2.4 KiB
JavaScript
80 lines
2.4 KiB
JavaScript
const crypto = require('node:crypto');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { reportErrorToRemote } = require('./report-error-to-remote');
|
|
|
|
const VIRTUAL_ROOT = path.join(__dirname, '../.metro-virtual');
|
|
const VIRTUAL_ROOT_UNRESOLVED = path.join(VIRTUAL_ROOT, 'unresolved');
|
|
|
|
const handleResolveRequestError = ({
|
|
error,
|
|
context,
|
|
moduleName,
|
|
platform,
|
|
}) => {
|
|
const errorMessage = `Unable to resolve module '${moduleName}' from '${context.originModulePath}'`;
|
|
const syntheticError = new Error(errorMessage);
|
|
syntheticError.stack = error.stack;
|
|
reportErrorToRemote({ error: syntheticError }).catch((_reportError) => {
|
|
// no-op
|
|
});
|
|
if (process.env.NODE_ENV === 'production') throw error;
|
|
if (platform === 'android') throw error;
|
|
if (!__DEV__ && process.env.EXPO_PUBLIC_CREATE_ENV !== 'DEVELOPMENT')
|
|
throw error;
|
|
|
|
// Build a deterministic virtual file path for this failed request
|
|
const key = `${moduleName}|${context.originModulePath}|${platform}`;
|
|
const hash = crypto
|
|
.createHash('sha256')
|
|
.update(key)
|
|
.digest('hex')
|
|
.slice(0, 16);
|
|
|
|
fs.mkdirSync(VIRTUAL_ROOT_UNRESOLVED, { recursive: true });
|
|
const vfile = path.join(VIRTUAL_ROOT_UNRESOLVED, `throw-${hash}.js`);
|
|
|
|
// Serialize a safe payload for the client
|
|
const payload = {
|
|
moduleName,
|
|
from: context.originModulePath,
|
|
platform,
|
|
originalMessage: String(
|
|
error?.message ? error.message : 'Unknown resolve error'
|
|
),
|
|
};
|
|
|
|
const code = [
|
|
'// Auto generated by custom Metro resolver',
|
|
'(function(){',
|
|
` var info = ${JSON.stringify(payload)};`,
|
|
" var msg = 'Unable to resolve \"' + info.moduleName + '\" from \"' + info.from + '\"';",
|
|
" msg += '\\n\\n' + info.originalMessage;",
|
|
' var e = new Error(msg);',
|
|
" e.name = 'ModuleResolveError';",
|
|
" e.code = 'MODULE_RESOLVE_FAILED';",
|
|
' throw e;',
|
|
'})();',
|
|
'export {};', // keep ESM shape harmlessly
|
|
'',
|
|
].join('\n');
|
|
|
|
// Only write if content changed — avoids bumping mtime and triggering Metro rebuild loop
|
|
const existingContent = fs.existsSync(vfile) ? fs.readFileSync(vfile, 'utf8') : null;
|
|
if (existingContent !== code) {
|
|
fs.writeFileSync(vfile, code, 'utf8');
|
|
}
|
|
|
|
// Tell Metro to load our thrower as a real source file
|
|
return {
|
|
filePath: vfile,
|
|
type: 'sourceFile',
|
|
};
|
|
};
|
|
|
|
module.exports = {
|
|
handleResolveRequestError,
|
|
VIRTUAL_ROOT,
|
|
VIRTUAL_ROOT_UNRESOLVED,
|
|
};
|