feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,21 @@
"use strict";
const Server = require("../../Server");
const asAssets = require("./RamBundle/as-assets");
const asIndexedFile = require("./RamBundle/as-indexed-file").save;
async function build(packagerClient, requestOptions) {
const options = {
...Server.DEFAULT_BUNDLE_OPTIONS,
...requestOptions,
bundleType: "ram",
};
return await packagerClient.getRamBundleInfo(options);
}
function save(bundle, options, log) {
return options.platform === "android" && !(options.indexedRamBundle === true)
? asAssets(bundle, options, log)
: asIndexedFile(bundle, options, log);
}
exports.build = build;
exports.save = save;
exports.formatName = "bundle";

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
'use strict';
import type {RamBundleInfo} from '../../DeltaBundler/Serializers/getRamBundleInfo';
import type {OutputOptions, RequestOptions} from '../types.flow';
const Server = require('../../Server');
const asAssets = require('./RamBundle/as-assets');
const asIndexedFile = require('./RamBundle/as-indexed-file').save;
async function build(
packagerClient: Server,
requestOptions: RequestOptions,
): Promise<RamBundleInfo> {
const options = {
...Server.DEFAULT_BUNDLE_OPTIONS,
...requestOptions,
bundleType: 'ram',
};
return await packagerClient.getRamBundleInfo(options);
}
function save(
bundle: RamBundleInfo,
options: OutputOptions,
log: (x: string) => void,
): Promise<mixed> {
// We fork here depending on the platform: while Android is pretty good at
// loading individual assets, iOS has a large overhead when reading hundreds
// of assets from disk.
return options.platform === 'android' && !(options.indexedRamBundle === true)
? asAssets(bundle, options, log)
: asIndexedFile(bundle, options, log);
}
exports.build = build;
exports.save = save;
exports.formatName = 'bundle';

View File

@@ -0,0 +1,74 @@
"use strict";
const relativizeSourceMapInline = require("../../../lib/relativizeSourceMap");
const writeFile = require("../writeFile");
const buildSourcemapWithMetadata = require("./buildSourcemapWithMetadata");
const MAGIC_RAM_BUNDLE_NUMBER = require("./magic-number");
const { joinModules } = require("./util");
const writeSourceMap = require("./write-sourcemap");
const fsPromises = require("fs").promises;
const path = require("path");
const MAGIC_RAM_BUNDLE_FILENAME = "UNBUNDLE";
const MODULES_DIR = "js-modules";
function saveAsAssets(bundle, options, log) {
const {
bundleOutput,
bundleEncoding: encoding,
sourcemapOutput,
sourcemapSourcesRoot,
} = options;
log("start");
const { startupModules, lazyModules } = bundle;
log("finish");
const startupCode = joinModules(startupModules);
log("Writing bundle output to:", bundleOutput);
const modulesDir = path.join(path.dirname(bundleOutput), MODULES_DIR);
const writeUnbundle = createDir(modulesDir).then(() =>
Promise.all([
writeModules(lazyModules, modulesDir, encoding),
writeFile(bundleOutput, startupCode, encoding),
writeMagicFlagFile(modulesDir),
])
);
writeUnbundle.then(() => log("Done writing unbundle output"));
if (sourcemapOutput) {
const sourceMap = buildSourcemapWithMetadata({
fixWrapperOffset: true,
lazyModules: lazyModules.concat(),
moduleGroups: null,
startupModules: startupModules.concat(),
});
if (sourcemapSourcesRoot != null) {
relativizeSourceMapInline(sourceMap, sourcemapSourcesRoot);
}
const wroteSourceMap = writeSourceMap(
sourcemapOutput,
JSON.stringify(sourceMap),
log
);
return Promise.all([writeUnbundle, wroteSourceMap]);
} else {
return writeUnbundle;
}
}
function createDir(dirName) {
return fsPromises.mkdir(dirName, {
recursive: true,
});
}
function writeModuleFile(module, modulesDir, encoding) {
const { code, id } = module;
return writeFile(path.join(modulesDir, id + ".js"), code, encoding);
}
function writeModules(modules, modulesDir, encoding) {
const writeFiles = modules.map((module) =>
writeModuleFile(module, modulesDir, encoding)
);
return Promise.all(writeFiles);
}
function writeMagicFlagFile(outputDir) {
const buffer = Buffer.alloc(4);
buffer.writeUInt32LE(MAGIC_RAM_BUNDLE_NUMBER, 0);
return writeFile(path.join(outputDir, MAGIC_RAM_BUNDLE_FILENAME), buffer);
}
module.exports = saveAsAssets;

View File

@@ -0,0 +1,127 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall react_native
*/
'use strict';
import type {RamBundleInfo} from '../../../DeltaBundler/Serializers/getRamBundleInfo';
import type {ModuleTransportLike} from '../../../shared/types.flow';
import type {OutputOptions} from '../../types.flow';
const relativizeSourceMapInline = require('../../../lib/relativizeSourceMap');
const writeFile = require('../writeFile');
const buildSourcemapWithMetadata = require('./buildSourcemapWithMetadata');
const MAGIC_RAM_BUNDLE_NUMBER = require('./magic-number');
const {joinModules} = require('./util');
const writeSourceMap = require('./write-sourcemap');
const fsPromises = require('fs').promises;
const path = require('path');
// must not start with a dot, as that won't go into the apk
const MAGIC_RAM_BUNDLE_FILENAME = 'UNBUNDLE';
const MODULES_DIR = 'js-modules';
/**
* Saves all JS modules of an app as single files
* The startup code (prelude, polyfills etc.) are written to the file
* designated by the `bundleOuput` option.
* All other modules go into a 'js-modules' folder that in the same parent
* directory as the startup file.
*/
function saveAsAssets(
bundle: RamBundleInfo,
options: OutputOptions,
log: (...args: Array<string>) => void,
): Promise<mixed> {
const {
bundleOutput,
bundleEncoding: encoding,
sourcemapOutput,
sourcemapSourcesRoot,
} = options;
log('start');
const {startupModules, lazyModules} = bundle;
log('finish');
const startupCode = joinModules(startupModules);
log('Writing bundle output to:', bundleOutput);
const modulesDir = path.join(path.dirname(bundleOutput), MODULES_DIR);
const writeUnbundle = createDir(modulesDir).then(
// create the modules directory first
() =>
Promise.all([
writeModules(lazyModules, modulesDir, encoding),
writeFile(bundleOutput, startupCode, encoding),
writeMagicFlagFile(modulesDir),
]),
);
// $FlowFixMe[unused-promise]
writeUnbundle.then(() => log('Done writing unbundle output'));
if (sourcemapOutput) {
const sourceMap = buildSourcemapWithMetadata({
fixWrapperOffset: true,
lazyModules: lazyModules.concat<
ModuleTransportLike,
ModuleTransportLike,
>(),
moduleGroups: null,
startupModules: startupModules.concat<
ModuleTransportLike,
ModuleTransportLike,
>(),
});
if (sourcemapSourcesRoot != null) {
relativizeSourceMapInline(sourceMap, sourcemapSourcesRoot);
}
const wroteSourceMap = writeSourceMap(
sourcemapOutput,
JSON.stringify(sourceMap),
log,
);
return Promise.all([writeUnbundle, wroteSourceMap]);
} else {
return writeUnbundle;
}
}
function createDir(dirName: string): Promise<void> {
return fsPromises.mkdir(dirName, {recursive: true});
}
function writeModuleFile(
module: ModuleTransportLike,
modulesDir: string,
encoding: void | 'ascii' | 'utf16le' | 'utf8',
): Promise<mixed> {
const {code, id} = module;
return writeFile(path.join(modulesDir, id + '.js'), code, encoding);
}
function writeModules(
modules: $ReadOnlyArray<ModuleTransportLike>,
modulesDir: string,
encoding: void | 'ascii' | 'utf16le' | 'utf8',
): Promise<Array<mixed>> {
const writeFiles = modules.map(
(module: ModuleTransportLike): Promise<mixed> =>
writeModuleFile(module, modulesDir, encoding),
);
return Promise.all(writeFiles);
}
function writeMagicFlagFile(outputDir: string): Promise<mixed> {
const buffer = Buffer.alloc(4);
buffer.writeUInt32LE(MAGIC_RAM_BUNDLE_NUMBER, 0);
return writeFile(path.join(outputDir, MAGIC_RAM_BUNDLE_FILENAME), buffer);
}
module.exports = saveAsAssets;

View File

@@ -0,0 +1,143 @@
"use strict";
const relativizeSourceMapInline = require("../../../lib/relativizeSourceMap");
const buildSourcemapWithMetadata = require("./buildSourcemapWithMetadata");
const MAGIC_UNBUNDLE_FILE_HEADER = require("./magic-number");
const { joinModules } = require("./util");
const writeSourceMap = require("./write-sourcemap");
const fs = require("fs");
const SIZEOF_UINT32 = 4;
function saveAsIndexedFile(bundle, options, log) {
const {
bundleOutput,
bundleEncoding: encoding,
sourcemapOutput,
sourcemapSourcesRoot,
} = options;
log("start");
const { startupModules, lazyModules, groups } = bundle;
log("finish");
const moduleGroups = createModuleGroups(groups, lazyModules);
const startupCode = joinModules(startupModules);
log("Writing unbundle output to:", bundleOutput);
const writeUnbundle = writeBuffers(
fs.createWriteStream(bundleOutput),
buildTableAndContents(startupCode, lazyModules, moduleGroups, encoding)
).then(() => log("Done writing unbundle output"));
if (sourcemapOutput) {
const sourceMap = buildSourcemapWithMetadata({
startupModules: startupModules.concat(),
lazyModules: lazyModules.concat(),
moduleGroups,
fixWrapperOffset: true,
});
if (sourcemapSourcesRoot != null) {
relativizeSourceMapInline(sourceMap, sourcemapSourcesRoot);
}
const wroteSourceMap = writeSourceMap(
sourcemapOutput,
JSON.stringify(sourceMap),
log
);
return Promise.all([writeUnbundle, wroteSourceMap]);
} else {
return writeUnbundle;
}
}
const fileHeader = Buffer.alloc(4);
fileHeader.writeUInt32LE(MAGIC_UNBUNDLE_FILE_HEADER, 0);
const nullByteBuffer = Buffer.alloc(1).fill(0);
function writeBuffers(stream, buffers) {
buffers.forEach((buffer) => stream.write(buffer));
return new Promise((resolve, reject) => {
stream.on("error", reject);
stream.on("finish", () => resolve());
stream.end();
});
}
function nullTerminatedBuffer(contents, encoding) {
return Buffer.concat([Buffer.from(contents, encoding), nullByteBuffer]);
}
function moduleToBuffer(id, code, encoding) {
return {
id,
buffer: nullTerminatedBuffer(code, encoding),
};
}
function entryOffset(n) {
return (2 + n * 2) * SIZEOF_UINT32;
}
function buildModuleTable(startupCode, moduleBuffers, moduleGroups) {
const moduleIds = [...moduleGroups.modulesById.keys()];
const maxId = moduleIds.reduce((max, id) => Math.max(max, id));
const numEntries = maxId + 1;
const table = Buffer.alloc(entryOffset(numEntries)).fill(0);
table.writeUInt32LE(numEntries, 0);
table.writeUInt32LE(startupCode.length, SIZEOF_UINT32);
let codeOffset = startupCode.length;
moduleBuffers.forEach(({ id, buffer }) => {
const group = moduleGroups.groups.get(id);
const idsInGroup = group ? [id].concat(Array.from(group)) : [id];
idsInGroup.forEach((moduleId) => {
const offset = entryOffset(moduleId);
table.writeUInt32LE(codeOffset, offset);
table.writeUInt32LE(buffer.length, offset + SIZEOF_UINT32);
});
codeOffset += buffer.length;
});
return table;
}
function groupCode(rootCode, moduleGroup, modulesById) {
if (!moduleGroup || !moduleGroup.size) {
return rootCode;
}
const code = [rootCode];
for (const id of moduleGroup) {
code.push(
(
modulesById.get(id) || {
code: "",
}
).code
);
}
return code.join("\n");
}
function buildModuleBuffers(modules, moduleGroups, encoding) {
return modules
.filter((m) => !moduleGroups.modulesInGroups.has(m.id))
.map(({ id, code }) =>
moduleToBuffer(
id,
groupCode(code, moduleGroups.groups.get(id), moduleGroups.modulesById),
encoding
)
);
}
function buildTableAndContents(startupCode, modules, moduleGroups, encoding) {
const startupCodeBuffer = nullTerminatedBuffer(startupCode, encoding);
const moduleBuffers = buildModuleBuffers(modules, moduleGroups, encoding);
const table = buildModuleTable(
startupCodeBuffer,
moduleBuffers,
moduleGroups
);
return [fileHeader, table, startupCodeBuffer].concat(
moduleBuffers.map(({ buffer }) => buffer)
);
}
function createModuleGroups(groups, modules) {
return {
groups,
modulesById: new Map(modules.map((m) => [m.id, m])),
modulesInGroups: new Set(concat(groups.values())),
};
}
function* concat(iterators) {
for (const it of iterators) {
yield* it;
}
}
exports.save = saveAsIndexedFile;
exports.buildTableAndContents = buildTableAndContents;
exports.createModuleGroups = createModuleGroups;

View File

@@ -0,0 +1,266 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall react_native
*/
'use strict';
import type {RamBundleInfo} from '../../../DeltaBundler/Serializers/getRamBundleInfo';
import type {
ModuleGroups,
ModuleTransportLike,
OutputOptions,
} from '../../types.flow';
import type {WriteStream} from 'fs';
const relativizeSourceMapInline = require('../../../lib/relativizeSourceMap');
const buildSourcemapWithMetadata = require('./buildSourcemapWithMetadata');
const MAGIC_UNBUNDLE_FILE_HEADER = require('./magic-number');
const {joinModules} = require('./util');
const writeSourceMap = require('./write-sourcemap');
const fs = require('fs');
const SIZEOF_UINT32 = 4;
/**
* Saves all JS modules of an app as a single file, separated with null bytes.
* The file begins with an offset table that contains module ids and their
* lengths/offsets.
* The module id for the startup code (prelude, polyfills etc.) is the
* empty string.
*/
function saveAsIndexedFile(
bundle: RamBundleInfo,
options: OutputOptions,
log: (...args: Array<string>) => void,
): Promise<mixed> {
const {
bundleOutput,
bundleEncoding: encoding,
sourcemapOutput,
sourcemapSourcesRoot,
} = options;
log('start');
const {startupModules, lazyModules, groups} = bundle;
log('finish');
const moduleGroups = createModuleGroups(groups, lazyModules);
const startupCode = joinModules(startupModules);
log('Writing unbundle output to:', bundleOutput);
const writeUnbundle = writeBuffers(
fs.createWriteStream(bundleOutput),
buildTableAndContents(startupCode, lazyModules, moduleGroups, encoding),
).then(() => log('Done writing unbundle output'));
if (sourcemapOutput) {
const sourceMap = buildSourcemapWithMetadata({
startupModules: startupModules.concat<
ModuleTransportLike,
ModuleTransportLike,
>(),
lazyModules: lazyModules.concat<
ModuleTransportLike,
ModuleTransportLike,
>(),
moduleGroups,
fixWrapperOffset: true,
});
if (sourcemapSourcesRoot != null) {
relativizeSourceMapInline(sourceMap, sourcemapSourcesRoot);
}
const wroteSourceMap = writeSourceMap(
sourcemapOutput,
JSON.stringify(sourceMap),
log,
);
return Promise.all([writeUnbundle, wroteSourceMap]);
} else {
return writeUnbundle;
}
}
const fileHeader = Buffer.alloc(4);
fileHeader.writeUInt32LE(MAGIC_UNBUNDLE_FILE_HEADER, 0);
const nullByteBuffer: Buffer = Buffer.alloc(1).fill(0);
function writeBuffers(
stream: WriteStream,
buffers: Array<Buffer>,
): Promise<void> {
buffers.forEach((buffer: Buffer) => stream.write(buffer));
return new Promise((resolve: () => void, reject: mixed => mixed) => {
stream.on('error', reject);
stream.on('finish', () => resolve());
stream.end();
});
}
function nullTerminatedBuffer(
contents: string,
encoding: void | 'ascii' | 'utf16le' | 'utf8',
): Buffer {
return Buffer.concat([Buffer.from(contents, encoding), nullByteBuffer]);
}
function moduleToBuffer(
id: number,
code: string,
encoding: void | 'ascii' | 'utf16le' | 'utf8',
): {buffer: Buffer, id: number} {
return {
id,
buffer: nullTerminatedBuffer(code, encoding),
};
}
function entryOffset(n: number): number {
// 2: num_entries + startup_code_len
// n * 2: each entry consists of two uint32s
return (2 + n * 2) * SIZEOF_UINT32;
}
function buildModuleTable(
startupCode: Buffer,
moduleBuffers: Array<{
buffer: Buffer,
id: number,
...
}>,
moduleGroups: ModuleGroups,
): Buffer {
// table format:
// - num_entries: uint_32 number of entries
// - startup_code_len: uint_32 length of the startup section
// - entries: entry...
//
// entry:
// - module_offset: uint_32 offset into the modules blob
// - module_length: uint_32 length of the module code in bytes
const moduleIds = [...moduleGroups.modulesById.keys()];
const maxId = moduleIds.reduce((max: number, id: number) =>
Math.max(max, id),
);
const numEntries = maxId + 1;
const table: Buffer = Buffer.alloc(entryOffset(numEntries)).fill(0);
// num_entries
table.writeUInt32LE(numEntries, 0);
// startup_code_len
table.writeUInt32LE(startupCode.length, SIZEOF_UINT32);
// entries
let codeOffset = startupCode.length;
moduleBuffers.forEach(({id, buffer}) => {
const group = moduleGroups.groups.get(id);
const idsInGroup: Array<number> = group
? [id].concat(Array.from(group))
: [id];
idsInGroup.forEach((moduleId: number) => {
const offset = entryOffset(moduleId);
// module_offset
table.writeUInt32LE(codeOffset, offset);
// module_length
table.writeUInt32LE(buffer.length, offset + SIZEOF_UINT32);
});
codeOffset += buffer.length;
});
return table;
}
function groupCode(
rootCode: string,
moduleGroup: void | Set<number>,
modulesById: Map<number, ModuleTransportLike>,
): string {
if (!moduleGroup || !moduleGroup.size) {
return rootCode;
}
const code = [rootCode];
for (const id of moduleGroup) {
code.push((modulesById.get(id) || {code: ''}).code);
}
return code.join('\n');
}
function buildModuleBuffers(
modules: $ReadOnlyArray<ModuleTransportLike>,
moduleGroups: ModuleGroups,
encoding: void | 'ascii' | 'utf16le' | 'utf8',
): Array<{
buffer: Buffer,
id: number,
...
}> {
return modules
.filter((m: ModuleTransportLike) => !moduleGroups.modulesInGroups.has(m.id))
.map(({id, code}) =>
moduleToBuffer(
id,
groupCode(code, moduleGroups.groups.get(id), moduleGroups.modulesById),
encoding,
),
);
}
function buildTableAndContents(
startupCode: string,
modules: $ReadOnlyArray<ModuleTransportLike>,
moduleGroups: ModuleGroups,
encoding?: 'utf8' | 'utf16le' | 'ascii',
): Array<Buffer> {
// file contents layout:
// - magic number char[4] 0xE5 0xD1 0x0B 0xFB (0xFB0BD1E5 uint32 LE)
// - offset table table see `buildModuleTables`
// - code blob char[] null-terminated code strings, starting with
// the startup code
const startupCodeBuffer = nullTerminatedBuffer(startupCode, encoding);
const moduleBuffers = buildModuleBuffers(modules, moduleGroups, encoding);
const table = buildModuleTable(
startupCodeBuffer,
moduleBuffers,
moduleGroups,
);
return [fileHeader, table, startupCodeBuffer].concat(
moduleBuffers.map(({buffer}) => buffer),
);
}
function createModuleGroups(
groups: Map<number, Set<number>>,
modules: $ReadOnlyArray<ModuleTransportLike>,
): ModuleGroups {
return {
groups,
modulesById: new Map(modules.map((m: ModuleTransportLike) => [m.id, m])),
modulesInGroups: new Set(concat(groups.values())),
};
}
function* concat(
iterators: Iterator<Set<number>>,
): Generator<number, void, void> {
for (const it of iterators) {
yield* it;
}
}
exports.save = saveAsIndexedFile;
exports.buildTableAndContents = buildTableAndContents;
exports.createModuleGroups = createModuleGroups;

View File

@@ -0,0 +1,42 @@
"use strict";
const {
combineSourceMaps,
combineSourceMapsAddingOffsets,
joinModules,
} = require("./util");
module.exports = ({
fixWrapperOffset,
lazyModules,
moduleGroups,
startupModules,
}) => {
const options = fixWrapperOffset
? {
fixWrapperOffset: true,
}
: undefined;
const startupModule = {
code: joinModules(startupModules),
id: Number.MIN_SAFE_INTEGER,
map: combineSourceMaps(startupModules, undefined, options),
sourcePath: "",
};
const module_paths = [];
startupModules.forEach((m) => {
module_paths[m.id] = m.sourcePath;
});
lazyModules.forEach((m) => {
module_paths[m.id] = m.sourcePath;
});
const map = combineSourceMapsAddingOffsets(
[startupModule].concat(lazyModules),
module_paths,
moduleGroups,
options
);
if (map.x_facebook_offsets != null) {
delete map.x_facebook_offsets[Number.MIN_SAFE_INTEGER];
}
return map;
};

View File

@@ -0,0 +1,64 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
'use strict';
import type {ModuleGroups, ModuleTransportLike} from '../../types.flow';
import type {IndexMap} from 'metro-source-map';
const {
combineSourceMaps,
combineSourceMapsAddingOffsets,
joinModules,
} = require('./util');
type Params = {
fixWrapperOffset: boolean,
lazyModules: $ReadOnlyArray<ModuleTransportLike>,
moduleGroups: ?ModuleGroups,
startupModules: $ReadOnlyArray<ModuleTransportLike>,
};
module.exports = (({
fixWrapperOffset,
lazyModules,
moduleGroups,
startupModules,
}: Params) => {
const options = fixWrapperOffset ? {fixWrapperOffset: true} : undefined;
const startupModule: ModuleTransportLike = {
code: joinModules(startupModules),
id: Number.MIN_SAFE_INTEGER,
map: combineSourceMaps(startupModules, undefined, options),
sourcePath: '',
};
// Add map of module id -> source to sourcemap
const module_paths = [];
startupModules.forEach((m: ModuleTransportLike) => {
module_paths[m.id] = m.sourcePath;
});
lazyModules.forEach((m: ModuleTransportLike) => {
module_paths[m.id] = m.sourcePath;
});
const map = combineSourceMapsAddingOffsets(
[startupModule].concat(lazyModules),
module_paths,
moduleGroups,
options,
);
if (map.x_facebook_offsets != null) {
delete map.x_facebook_offsets[Number.MIN_SAFE_INTEGER];
}
return map;
}: Params => IndexMap);

View File

@@ -0,0 +1,3 @@
"use strict";
module.exports = 0xfb0bd1e5;

View File

@@ -0,0 +1,14 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
* @oncall react_native
*/
'use strict';
module.exports = 0xfb0bd1e5;

View File

@@ -0,0 +1,104 @@
"use strict";
var _countLines = _interopRequireDefault(require("../../../lib/countLines"));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
const invariant = require("invariant");
function lineToLineSourceMap(source, filename = "") {
const firstLine = "AAAA;";
const line = "AACA;";
return {
file: filename,
mappings: firstLine + Array((0, _countLines.default)(source)).join(line),
sources: [filename],
names: [],
version: 3,
};
}
const wrapperEnd = (wrappedCode) => wrappedCode.indexOf("{") + 1;
const Section = (line, column, map) => ({
map,
offset: {
line,
column,
},
});
function combineSourceMaps(modules, moduleGroups, options) {
const sections = combineMaps(modules, null, moduleGroups, options);
return {
sections,
version: 3,
};
}
function combineSourceMapsAddingOffsets(
modules,
x_metro_module_paths,
moduleGroups,
options
) {
const x_facebook_offsets = [];
const sections = combineMaps(
modules,
x_facebook_offsets,
moduleGroups,
options
);
return {
sections,
version: 3,
x_facebook_offsets,
x_metro_module_paths,
};
}
function combineMaps(modules, offsets, moduleGroups, options) {
const sections = [];
let line = 0;
modules.forEach((moduleTransport) => {
const { code, id, name } = moduleTransport;
let column = 0;
let group;
let groupLines = 0;
let { map } = moduleTransport;
if (moduleGroups && moduleGroups.modulesInGroups.has(id)) {
return;
}
if (offsets != null) {
group = moduleGroups && moduleGroups.groups.get(id);
if (group && moduleGroups) {
const { modulesById } = moduleGroups;
const otherModules = Array.from(group || [])
.map((moduleId) => modulesById.get(moduleId))
.filter(Boolean);
otherModules.forEach((m) => {
groupLines += (0, _countLines.default)(m.code);
});
map = combineSourceMaps([moduleTransport].concat(otherModules));
}
column = options && options.fixWrapperOffset ? wrapperEnd(code) : 0;
}
invariant(
!Array.isArray(map),
"Random Access Bundle source maps cannot be built from raw mappings"
);
sections.push(
Section(line, column, map || lineToLineSourceMap(code, name))
);
if (offsets != null && id != null) {
offsets[id] = line;
for (const moduleId of group || []) {
offsets[moduleId] = line;
}
}
line += (0, _countLines.default)(code) + groupLines;
});
return sections;
}
const joinModules = (modules) => modules.map((m) => m.code).join("\n");
module.exports = {
combineSourceMaps,
combineSourceMapsAddingOffsets,
countLines: _countLines.default,
joinModules,
lineToLineSourceMap,
};

View File

@@ -0,0 +1,147 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
'use strict';
import type {ModuleGroups, ModuleTransportLike} from '../../types.flow';
import type {
BasicSourceMap,
IndexMap,
IndexMapSection,
MixedSourceMap,
} from 'metro-source-map';
import countLines from '../../../lib/countLines';
const invariant = require('invariant');
function lineToLineSourceMap(
source: string,
filename: string = '',
): BasicSourceMap {
// The first line mapping in our package is the base64vlq code for zeros (A).
const firstLine = 'AAAA;';
// Most other lines in our mappings are all zeros (for module, column etc)
// except for the lineno mapping: curLineno - prevLineno = 1; Which is C.
const line = 'AACA;';
return {
file: filename,
mappings: firstLine + Array(countLines(source)).join(line),
sources: [filename],
names: [],
version: 3,
};
}
const wrapperEnd = (wrappedCode: string) => wrappedCode.indexOf('{') + 1;
const Section = (line: number, column: number, map: MixedSourceMap) => ({
map,
offset: {line, column},
});
type CombineOptions = {fixWrapperOffset: boolean, ...};
function combineSourceMaps(
modules: $ReadOnlyArray<ModuleTransportLike>,
moduleGroups?: ModuleGroups,
options?: ?CombineOptions,
): IndexMap {
const sections = combineMaps(modules, null, moduleGroups, options);
return {sections, version: 3};
}
function combineSourceMapsAddingOffsets(
modules: $ReadOnlyArray<ModuleTransportLike>,
x_metro_module_paths: Array<string>,
moduleGroups?: ?ModuleGroups,
options?: ?CombineOptions,
): IndexMap {
const x_facebook_offsets: Array<number> = [];
const sections = combineMaps(
modules,
x_facebook_offsets,
moduleGroups,
options,
);
return {sections, version: 3, x_facebook_offsets, x_metro_module_paths};
}
function combineMaps(
modules: $ReadOnlyArray<ModuleTransportLike>,
offsets: ?Array<number>,
moduleGroups: ?ModuleGroups,
options: ?CombineOptions,
): Array<IndexMapSection> {
const sections = [];
let line = 0;
modules.forEach((moduleTransport: ModuleTransportLike) => {
const {code, id, name} = moduleTransport;
let column = 0;
let group;
let groupLines = 0;
let {map} = moduleTransport;
if (moduleGroups && moduleGroups.modulesInGroups.has(id)) {
// this is a module appended to another module
return;
}
if (offsets != null) {
group = moduleGroups && moduleGroups.groups.get(id);
if (group && moduleGroups) {
const {modulesById} = moduleGroups;
const otherModules: $ReadOnlyArray<ModuleTransportLike> = Array.from(
group || [],
)
.map((moduleId: number) => modulesById.get(moduleId))
.filter(Boolean); // needed to appease flow
otherModules.forEach((m: ModuleTransportLike) => {
groupLines += countLines(m.code);
});
map = combineSourceMaps([moduleTransport].concat(otherModules));
}
column = options && options.fixWrapperOffset ? wrapperEnd(code) : 0;
}
invariant(
!Array.isArray(map),
'Random Access Bundle source maps cannot be built from raw mappings',
);
sections.push(
Section(line, column, map || lineToLineSourceMap(code, name)),
);
if (offsets != null && id != null) {
offsets[id] = line;
for (const moduleId of group || []) {
offsets[moduleId] = line;
}
}
line += countLines(code) + groupLines;
});
return sections;
}
const joinModules = (modules: $ReadOnlyArray<{+code: string, ...}>): string =>
modules.map((m: {+code: string, ...}) => m.code).join('\n');
module.exports = {
combineSourceMaps,
combineSourceMapsAddingOffsets,
countLines,
joinModules,
lineToLineSourceMap,
};

View File

@@ -0,0 +1,13 @@
"use strict";
const writeFile = require("../writeFile");
function writeSourcemap(fileName, contents, log) {
if (!fileName) {
return Promise.resolve();
}
log("Writing sourcemap output to:", fileName);
const writeMap = writeFile(fileName, contents, null);
writeMap.then(() => log("Done writing sourcemap output"));
return writeMap;
}
module.exports = writeSourcemap;

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
'use strict';
const writeFile = require('../writeFile');
function writeSourcemap(
fileName: string,
contents: string,
log: (...args: Array<string>) => void,
): Promise<mixed> {
if (!fileName) {
return Promise.resolve();
}
log('Writing sourcemap output to:', fileName);
const writeMap = writeFile(fileName, contents, null);
// $FlowFixMe[unused-promise]
writeMap.then(() => log('Done writing sourcemap output'));
return writeMap;
}
module.exports = writeSourcemap;

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @oncall react_native
*/
import Server from '../../Server';
import {OutputOptions, RequestOptions} from '../../shared/types';
export function build(
packagerClient: Server,
requestOptions: RequestOptions,
): Promise<{
code: string;
map: string;
}>;
export function save(
bundle: {
code: string;
map: string;
},
options: OutputOptions,
log: (...args: string[]) => void,
): Promise<unknown>;
export const formatName: string;

View File

@@ -0,0 +1,48 @@
"use strict";
const relativizeSourceMapInline = require("../../lib/relativizeSourceMap");
const Server = require("../../Server");
const writeFile = require("./writeFile");
function buildBundle(packagerClient, requestOptions) {
return packagerClient.build({
...Server.DEFAULT_BUNDLE_OPTIONS,
...requestOptions,
bundleType: "bundle",
});
}
function relativateSerializedMap(map, sourceMapSourcesRoot) {
const sourceMap = JSON.parse(map);
relativizeSourceMapInline(sourceMap, sourceMapSourcesRoot);
return JSON.stringify(sourceMap);
}
async function saveBundleAndMap(bundle, options, log) {
const {
bundleOutput,
bundleEncoding: encoding,
sourcemapOutput,
sourcemapSourcesRoot,
} = options;
const writeFns = [];
writeFns.push(async () => {
log(`Writing bundle output to: ${bundleOutput}`);
await writeFile(bundleOutput, bundle.code, encoding);
log("Done writing bundle output");
});
if (sourcemapOutput) {
let { map } = bundle;
if (sourcemapSourcesRoot != null) {
log("start relativating source map");
map = relativateSerializedMap(map, sourcemapSourcesRoot);
log("finished relativating");
}
writeFns.push(async () => {
log(`Writing sourcemap output to: ${sourcemapOutput}`);
await writeFile(sourcemapOutput, map, null);
log("Done writing sourcemap output");
});
}
await Promise.all(writeFns.map((cb) => cb()));
}
exports.build = buildBundle;
exports.save = saveBundleAndMap;
exports.formatName = "bundle";

View File

@@ -0,0 +1,90 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall react_native
*/
'use strict';
import type {OutputOptions, RequestOptions} from '../types.flow';
import type {MixedSourceMap} from 'metro-source-map';
const relativizeSourceMapInline = require('../../lib/relativizeSourceMap');
const Server = require('../../Server');
const writeFile = require('./writeFile');
function buildBundle(
packagerClient: Server,
requestOptions: RequestOptions,
): Promise<{
code: string,
map: string,
...
}> {
return packagerClient.build({
...Server.DEFAULT_BUNDLE_OPTIONS,
...requestOptions,
bundleType: 'bundle',
});
}
function relativateSerializedMap(
map: string,
sourceMapSourcesRoot: string,
): string {
const sourceMap: MixedSourceMap = JSON.parse(map);
relativizeSourceMapInline(sourceMap, sourceMapSourcesRoot);
return JSON.stringify(sourceMap);
}
async function saveBundleAndMap(
bundle: {
code: string,
map: string,
...
},
options: OutputOptions,
log: (...args: Array<string>) => void,
): Promise<mixed> {
const {
bundleOutput,
bundleEncoding: encoding,
sourcemapOutput,
sourcemapSourcesRoot,
} = options;
const writeFns = [];
writeFns.push(async () => {
log(`Writing bundle output to: ${bundleOutput}`);
await writeFile(bundleOutput, bundle.code, encoding);
log('Done writing bundle output');
});
if (sourcemapOutput) {
let {map} = bundle;
if (sourcemapSourcesRoot != null) {
log('start relativating source map');
map = relativateSerializedMap(map, sourcemapSourcesRoot);
log('finished relativating');
}
writeFns.push(async () => {
log(`Writing sourcemap output to: ${sourcemapOutput}`);
await writeFile(sourcemapOutput, map, null);
log('Done writing sourcemap output');
});
}
// Wait until everything is written to disk.
await Promise.all(writeFns.map((cb: void => mixed) => cb()));
}
exports.build = buildBundle;
exports.save = saveBundleAndMap;
exports.formatName = 'bundle';

View File

@@ -0,0 +1,6 @@
"use strict";
try {
require("metro-babel-register").unstable_registerForMetroMonorepo();
} catch {}
module.exports = require("./bundle.flow");

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
'use strict';
/*::
export type * from './bundle.flow';
*/
try {
require('metro-babel-register').unstable_registerForMetroMonorepo();
} catch {}
module.exports = require('./bundle.flow');

View File

@@ -0,0 +1,42 @@
"use strict";
const crypto = require("crypto");
const isUTF8 = (encoding) => /^utf-?8$/i.test(encoding);
const constantFor = (encoding) =>
/^ascii$/i.test(encoding)
? 1
: isUTF8(encoding)
? 2
: /^(?:utf-?16(?:le)?|ucs-?2)$/.test(encoding)
? 3
: 0;
module.exports = function (code, encoding = "utf8") {
const buffer = asBuffer(code, encoding);
const hash = crypto.createHash("sha1");
hash.update(buffer);
const digest = hash.digest("buffer");
const signature = Buffer.alloc(digest.length + 1);
digest.copy(signature);
signature.writeUInt8(
constantFor(tryAsciiPromotion(buffer, encoding)),
signature.length - 1
);
return signature;
};
function tryAsciiPromotion(buffer, encoding) {
if (!isUTF8(encoding)) {
return encoding;
}
for (let i = 0, n = buffer.length; i < n; i++) {
if (buffer[i] > 0x7f) {
return encoding;
}
}
return "ascii";
}
function asBuffer(x, encoding) {
if (typeof x !== "string") {
return x;
}
return Buffer.from(x, encoding);
}

View File

@@ -0,0 +1,68 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
* @oncall react_native
*/
'use strict';
const crypto = require('crypto');
const isUTF8 = (encoding: 'ascii' | 'utf16le' | 'utf8') =>
/^utf-?8$/i.test(encoding);
const constantFor = (encoding: 'ascii' | 'utf16le' | 'utf8') =>
/^ascii$/i.test(encoding)
? 1
: isUTF8(encoding)
? 2
: /^(?:utf-?16(?:le)?|ucs-?2)$/.test(encoding)
? 3
: 0;
module.exports = function (
code: Buffer | string,
encoding: 'ascii' | 'utf16le' | 'utf8' = 'utf8',
): Buffer {
const buffer: Buffer = asBuffer(code, encoding);
const hash = crypto.createHash('sha1');
hash.update(buffer);
const digest = hash.digest('buffer');
const signature = Buffer.alloc(digest.length + 1);
digest.copy(signature);
signature.writeUInt8(
constantFor(tryAsciiPromotion(buffer, encoding)),
signature.length - 1,
);
return signature;
};
function tryAsciiPromotion(
buffer: Buffer,
encoding: 'ascii' | 'utf16le' | 'utf8',
): 'ascii' | 'utf16le' | 'utf8' {
if (!isUTF8(encoding)) {
return encoding;
}
for (let i = 0, n = buffer.length; i < n; i++) {
if (buffer[i] > 0x7f) {
return encoding;
}
}
return 'ascii';
}
function asBuffer(
x: Buffer | string,
encoding: 'ascii' | 'utf16le' | 'utf8',
): Buffer {
if (typeof x !== 'string') {
return x;
}
return Buffer.from(x, encoding);
}

View File

@@ -0,0 +1,3 @@
"use strict";
module.exports = require("./RamBundle");

View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
'use strict';
/* This is for retro-compatibility of React Native with older versions of
* Metro. Use the `RamBundle` module directly. */
module.exports = require('./RamBundle');

View File

@@ -0,0 +1,7 @@
"use strict";
const denodeify = require("denodeify");
const fs = require("fs");
const throat = require("throat");
const writeFile = throat(128, denodeify(fs.writeFile));
module.exports = writeFile;

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall react_native
*/
'use strict';
const denodeify = require('denodeify');
const fs = require('fs');
const throat = require('throat');
type WriteFn = (
file: string,
data: string | Buffer,
encoding?: ?string,
) => Promise<mixed>;
const writeFile: WriteFn = throat(128, denodeify(fs.writeFile));
module.exports = writeFile;

View File

@@ -0,0 +1,139 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @oncall react_native
*/
import type {
Options as DeltaBundlerOptions,
TransformInputOptions,
} from '../DeltaBundler/types';
import type {TransformProfile} from 'metro-babel-transformer';
import type {CustomResolverOptions} from 'metro-resolver';
import type {
MetroSourceMapSegmentTuple,
MixedSourceMap,
} from 'metro-source-map';
import type {
CustomTransformOptions,
MinifierOptions,
} from 'metro-transform-worker';
export type BundleType =
| 'bundle'
| 'delta'
| 'meta'
| 'map'
| 'ram'
| 'cli'
| 'hmr'
| 'todo'
| 'graph';
type MetroSourceMapOrMappings = MixedSourceMap | MetroSourceMapSegmentTuple[];
export interface BundleOptions {
bundleType: BundleType;
readonly customResolverOptions: CustomResolverOptions;
customTransformOptions: CustomTransformOptions;
dev: boolean;
entryFile: string;
readonly excludeSource: boolean;
readonly hot: boolean;
readonly inlineSourceMap: boolean;
readonly lazy: boolean;
minify: boolean;
readonly modulesOnly: boolean;
onProgress?: (doneCont: number, totalCount: number) => unknown;
readonly platform?: string;
readonly runModule: boolean;
runtimeBytecodeVersion?: number;
readonly shallow: boolean;
sourceMapUrl?: string;
sourceUrl?: string;
createModuleIdFactory?: () => (path: string) => number;
readonly unstable_transformProfile: TransformProfile;
}
export interface ResolverInputOptions {
readonly customResolverOptions?: CustomResolverOptions;
}
export interface SerializerOptions {
readonly sourceMapUrl: string | null;
readonly sourceUrl: string | null;
readonly runModule: boolean;
readonly excludeSource: boolean;
readonly inlineSourceMap: boolean;
readonly modulesOnly: boolean;
}
export interface GraphOptions {
readonly lazy: boolean;
readonly shallow: boolean;
}
// Stricter representation of BundleOptions.
export interface SplitBundleOptions {
readonly entryFile: string;
readonly resolverOptions: ResolverInputOptions;
readonly transformOptions: TransformInputOptions;
readonly serializerOptions: SerializerOptions;
readonly graphOptions: GraphOptions;
readonly onProgress: DeltaBundlerOptions['onProgress'];
}
export interface ModuleGroups {
groups: Map<number, Set<number>>;
modulesById: Map<number, ModuleTransportLike>;
modulesInGroups: Set<number>;
}
export interface ModuleTransportLike {
readonly code: string;
readonly id: number;
readonly map: MetroSourceMapOrMappings | null;
readonly name?: string;
readonly sourcePath: string;
}
export interface ModuleTransportLikeStrict {
readonly code: string;
readonly id: number;
readonly map: MetroSourceMapOrMappings | null;
readonly name?: string;
readonly sourcePath: string;
}
export interface RamModuleTransport extends ModuleTransportLikeStrict {
readonly source: string;
readonly type: string;
}
export interface OutputOptions {
bundleOutput: string;
bundleEncoding?: 'utf8' | 'utf16le' | 'ascii';
dev?: boolean;
indexedRamBundle?: boolean;
platform: string;
sourcemapOutput?: string;
sourcemapSourcesRoot?: string;
sourcemapUseAbsolutePath?: boolean;
}
export interface RequestOptions {
entryFile: string;
inlineSourceMap?: boolean;
sourceMapUrl?: string;
dev?: boolean;
minify: boolean;
platform: string;
createModuleIdFactory?: () => (path: string) => number;
onProgress?: (transformedFileCount: number, totalFileCount: number) => void;
}
export type {MinifierOptions};

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.SourcePathsMode = void 0;
const SourcePathsMode = require("flow-enums-runtime")({
Absolute: "absolute",
ServerUrl: "url-server",
});
exports.SourcePathsMode = SourcePathsMode;

View File

@@ -0,0 +1,156 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
'use strict';
import type {
Options as DeltaBundlerOptions,
TransformInputOptions,
} from '../DeltaBundler/types.flow';
import type {TransformProfile} from 'metro-babel-transformer';
import type {CustomResolverOptions} from 'metro-resolver';
import type {
MetroSourceMapSegmentTuple,
MixedSourceMap,
} from 'metro-source-map';
import type {
CustomTransformOptions,
MinifierOptions,
} from 'metro-transform-worker';
type BundleType =
| 'bundle'
| 'delta'
| 'meta'
| 'map'
| 'ram'
| 'cli'
| 'hmr'
| 'todo'
| 'graph';
type MetroSourceMapOrMappings =
| MixedSourceMap
| Array<MetroSourceMapSegmentTuple>;
export enum SourcePathsMode {
/* Use absolute paths for source files in source maps (default). */
Absolute = 'absolute',
/* Use server-relative URL paths for source files in source maps. */
ServerUrl = 'url-server',
}
export type BundleOptions = {
bundleType: BundleType,
+customResolverOptions: CustomResolverOptions,
customTransformOptions: CustomTransformOptions,
dev: boolean,
entryFile: string,
+excludeSource: boolean,
+hot: boolean,
+inlineSourceMap: boolean,
+lazy: boolean,
minify: boolean,
+modulesOnly: boolean,
onProgress: ?(doneCont: number, totalCount: number) => mixed,
+platform: ?string,
+runModule: boolean,
+shallow: boolean,
sourceMapUrl: ?string,
sourceUrl: ?string,
createModuleIdFactory?: () => (path: string) => number,
+unstable_transformProfile: TransformProfile,
+sourcePaths: SourcePathsMode,
};
export type ResolverInputOptions = $ReadOnly<{
customResolverOptions?: CustomResolverOptions,
dev: boolean,
}>;
export type SerializerOptions = {
+sourceMapUrl: ?string,
+sourceUrl: ?string,
+runModule: boolean,
+excludeSource: boolean,
+inlineSourceMap: boolean,
+modulesOnly: boolean,
+sourcePaths: SourcePathsMode,
};
export type GraphOptions = {
+lazy: boolean,
+shallow: boolean,
};
// Stricter representation of BundleOptions.
export type SplitBundleOptions = {
+entryFile: string,
+resolverOptions: ResolverInputOptions,
+transformOptions: TransformInputOptions,
+serializerOptions: SerializerOptions,
+graphOptions: GraphOptions,
+onProgress: $PropertyType<DeltaBundlerOptions<>, 'onProgress'>,
};
export type ModuleGroups = {
groups: Map<number, Set<number>>,
modulesById: Map<number, ModuleTransportLike>,
modulesInGroups: Set<number>,
};
export type ModuleTransportLike = {
+code: string,
+id: number,
+map: ?MetroSourceMapOrMappings,
+name?: string,
+sourcePath: string,
...
};
export type ModuleTransportLikeStrict = {
+code: string,
+id: number,
+map: ?MetroSourceMapOrMappings,
+name?: string,
+sourcePath: string,
};
export type RamModuleTransport = {
...ModuleTransportLikeStrict,
+source: string,
+type: string,
};
export type OutputOptions = {
bundleOutput: string,
bundleEncoding?: 'utf8' | 'utf16le' | 'ascii',
dev?: boolean,
indexedRamBundle?: boolean,
platform: string,
sourcemapOutput?: string,
sourcemapSourcesRoot?: string,
sourcemapUseAbsolutePath?: boolean,
...
};
export type RequestOptions = {
entryFile: string,
inlineSourceMap?: boolean,
sourceMapUrl?: string,
dev?: boolean,
minify: boolean,
platform: string,
createModuleIdFactory?: () => (path: string) => number,
onProgress?: (transformedFileCount: number, totalFileCount: number) => void,
+customResolverOptions?: CustomResolverOptions,
+customTransformOptions?: CustomTransformOptions,
};
export type {MinifierOptions};