@zntc/react-native 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/dev-server/hmr-bridge.d.ts +22 -0
- package/dist/dev-server/http-server.d.ts +32 -0
- package/dist/dev-server/http-utils.d.ts +11 -0
- package/dist/dev-server/index.d.ts +18 -0
- package/dist/dev-server/logger.d.ts +35 -0
- package/dist/dev-server/middleware/cli-server-api.d.ts +25 -0
- package/dist/dev-server/middleware/dev-middleware.d.ts +33 -0
- package/dist/dev-server/options.d.ts +30 -0
- package/dist/dev-server/platform-state.d.ts +37 -0
- package/dist/dev-server/routes/_shared.d.ts +3 -0
- package/dist/dev-server/routes/assets.d.ts +12 -0
- package/dist/dev-server/routes/bundle.d.ts +8 -0
- package/dist/dev-server/routes/devmenu.d.ts +4 -0
- package/dist/dev-server/routes/index-page.d.ts +3 -0
- package/dist/dev-server/routes/open-url.d.ts +4 -0
- package/dist/dev-server/routes/reload.d.ts +4 -0
- package/dist/dev-server/routes/status.d.ts +3 -0
- package/dist/dev-server/routes/symbolicate.d.ts +5 -0
- package/dist/dev-server/serve.d.ts +27 -0
- package/dist/dev-server/sourcemap.d.ts +15 -0
- package/dist/dev-server/symbolicate-source.d.ts +54 -0
- package/dist/dev-server/terminal-actions.d.ts +32 -0
- package/dist/dev-server/types.d.ts +22 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +3471 -0
- package/dist/metro-hmr-adapter.d.ts +29 -0
- package/dist/metro-resolver-types.d.ts +39 -0
- package/dist/plugins/asset.d.ts +11 -0
- package/dist/plugins/babel.d.ts +42 -0
- package/dist/plugins/codegen.d.ts +16 -0
- package/dist/plugins/escape-regex.d.ts +1 -0
- package/dist/plugins/internal.d.ts +37 -0
- package/dist/plugins/metro-resolve-request.d.ts +7 -0
- package/dist/plugins/require-context.d.ts +7 -0
- package/dist/plugins/styled-components-native.d.ts +11 -0
- package/dist/plugins/types.d.ts +25 -0
- package/dist/preset.d.ts +142 -0
- package/dist/rn-constants.d.ts +21 -0
- package/dist/runtime-loader.d.ts +14 -0
- package/dist/withExpo.d.ts +60 -0
- package/package.json +70 -0
- package/runtime/.gitkeep +0 -0
- package/runtime/zntc-hmr-client.cjs +328 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ohah
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# @zntc/react-native
|
|
2
|
+
|
|
3
|
+
ZNTC 의 React Native platform layer (#2540).
|
|
4
|
+
|
|
5
|
+
## 역할
|
|
6
|
+
|
|
7
|
+
- **RN preset** — `buildRnBundleOptions(input)` / `bundleRn(input)` / `watchRn(input)`. RN-specific NAPI build 옵션 (target=es5, flow, jsx=automatic-dev, devMode, reactRefresh, polyfills, runBeforeMain, banner) 자동 적용.
|
|
8
|
+
- **Metro HMR adapter** — `createMetroHmrAdapter()` (`@zntc/server.HmrChannel` 위 thin wrapper). RN runtime 의 HMRClient interface 호환 메시지 (`hmr:update-start` / `hmr:update` / `hmr:update-done` / `hmr:reload` / `hmr:error` / `log`) 송출.
|
|
9
|
+
- **RN runtime** — `runtime/zntc-hmr-client.cjs` (Metro HMRClient 인터페이스 호환 RN runtime).
|
|
10
|
+
- **Plugin factories** — `createAssetPlugin` / `createBabelPlugin` / `createCodegenPlugin` / `createRequireContextPlugin` / `createMetroResolveRequestPlugin`.
|
|
11
|
+
- **RN 상수 / helpers** — `RN_GLOBAL_IDENTIFIERS` / `tryResolve` / `resolveRnPolyfills`.
|
|
12
|
+
|
|
13
|
+
## 비범위 (이 패키지가 안 함)
|
|
14
|
+
|
|
15
|
+
- HTTP server / dev-middleware / asset registry / Rozenite DevTools / open-stack-frame / symbolicate — RN-specific runtime 영역, 사용자 측 (예: bungae) 가 운영
|
|
16
|
+
- iOS / Android native build orchestration (run-android / run-ios / autolinking) — `@react-native-community/cli` 영역
|
|
17
|
+
|
|
18
|
+
## 설치
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bun add -D @zntc/react-native @zntc/core
|
|
22
|
+
# 사용 환경에 따라 optional:
|
|
23
|
+
# bun add -D @babel/core @react-native/babel-preset metro-resolver react-native
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 사용 예
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { init, build } from '@zntc/core';
|
|
30
|
+
import { buildRnBundleOptions } from '@zntc/react-native';
|
|
31
|
+
|
|
32
|
+
await init();
|
|
33
|
+
const result = await build(
|
|
34
|
+
buildRnBundleOptions({
|
|
35
|
+
entry: '/abs/path/index.ts',
|
|
36
|
+
projectRoot: '/abs/path',
|
|
37
|
+
rnPlatform: 'ios',
|
|
38
|
+
dev: false,
|
|
39
|
+
sourcemap: true,
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 관련 epic
|
|
45
|
+
|
|
46
|
+
- #2539 — `@zntc/web` + `@zntc/server` 분리 (선행, 완료)
|
|
47
|
+
- #2540 — 본 패키지 신설
|
|
48
|
+
- #2538 — Zig 단일 dev server (후속)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IncomingMessage } from 'node:http';
|
|
2
|
+
import type { Socket } from 'node:net';
|
|
3
|
+
import { type MetroHmrAdapter } from '../metro-hmr-adapter.ts';
|
|
4
|
+
import type { PlatformStateCallbacks } from './platform-state.ts';
|
|
5
|
+
export interface HmrBridgeOptions {
|
|
6
|
+
/** ws path. Metro 호환 default `/hot`. */
|
|
7
|
+
readonly path: string;
|
|
8
|
+
/** rebuild log 출력 비활성 (test 환경). default false. */
|
|
9
|
+
readonly silent?: boolean;
|
|
10
|
+
/** Metro `server.forwardClientLogs` 호환. default true. */
|
|
11
|
+
readonly forwardClientLogs?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface HmrBridge {
|
|
14
|
+
readonly adapter: MetroHmrAdapter;
|
|
15
|
+
readonly callbacks: PlatformStateCallbacks;
|
|
16
|
+
readonly path: string;
|
|
17
|
+
/** http upgrade chain 안에서 호출 — channel.accept + initial greeting. */
|
|
18
|
+
acceptUpgrade(req: IncomingMessage, socket: Socket): void;
|
|
19
|
+
/** RN runtime console.log forwarding 출력 표시 toggle. 새 상태 반환. */
|
|
20
|
+
toggleLogs(): boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function createHmrBridge(options: HmrBridgeOptions): HmrBridge;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Server } from 'node:http';
|
|
2
|
+
import type { HmrBridge } from './hmr-bridge.ts';
|
|
3
|
+
import type { CliServerApi } from './middleware/cli-server-api.ts';
|
|
4
|
+
import { type DevMiddleware } from './middleware/dev-middleware.ts';
|
|
5
|
+
import type { RnDevServerOptions } from './options.ts';
|
|
6
|
+
import type { PlatformStateRegistry } from './platform-state.ts';
|
|
7
|
+
import type { Broadcast, Middleware } from './types.ts';
|
|
8
|
+
export interface DevHttpServerDeps {
|
|
9
|
+
/** WS broadcast — caller 가 cli-server-api 의 messageSocketEndpoint.broadcast 와 wire. */
|
|
10
|
+
broadcast: Broadcast;
|
|
11
|
+
/** per-platform state — bundle/map/hmr-map 라우트가 plat 분기 시 사용. */
|
|
12
|
+
platforms: PlatformStateRegistry;
|
|
13
|
+
/** HMR bridge — `/hot` upgrade 핸들 + adapter. 미지정 시 HMR 비활성. */
|
|
14
|
+
hmrBridge?: HmrBridge;
|
|
15
|
+
/** RN DevTools dev-middleware (peer optional). 미지정 시 inspector 비활성. */
|
|
16
|
+
devMiddleware?: DevMiddleware;
|
|
17
|
+
/** cli-server-api 의 websocket endpoints (peer optional). */
|
|
18
|
+
cliServerApi?: CliServerApi;
|
|
19
|
+
}
|
|
20
|
+
export interface DevHttpServerHandle {
|
|
21
|
+
readonly server: Server;
|
|
22
|
+
readonly url: string;
|
|
23
|
+
readonly port: number;
|
|
24
|
+
stop(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Base middleware — status/reload/devmenu/open-url 4 라우트만 처리. 매칭 못
|
|
28
|
+
* 한 path 는 next() 로 위임. user enhanceMiddleware (rozenite 등) 가 chain
|
|
29
|
+
* 의 어느 layer 든 가로챌 수 있도록 connect-style next 호출.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createBaseMiddleware(options: RnDevServerOptions, deps: DevHttpServerDeps): Middleware;
|
|
32
|
+
export declare function createDevHttpServer(options: RnDevServerOptions, deps: DevHttpServerDeps): Promise<DevHttpServerHandle>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
export declare function sendText(res: ServerResponse, statusCode: number, text: string, contentType?: string): void;
|
|
3
|
+
export declare function sendJson(res: ServerResponse, statusCode: number, data: unknown): void;
|
|
4
|
+
/**
|
|
5
|
+
* POST body 를 JSON 으로 read. Connect/Express middleware (e.g. cli-server-api
|
|
6
|
+
* 의 rawBodyMiddleware, @rozenite/middleware 의 express.json()) 가 stream 을 미리
|
|
7
|
+
* drain 한 경우 augmented `req.body` / `req.rawBody` 에서 복구 — 그렇지 않으면
|
|
8
|
+
* `req.on('data')` 가 영원히 발화 안 해 hang.
|
|
9
|
+
*/
|
|
10
|
+
export declare function readJsonBody<T>(req: IncomingMessage): Promise<T>;
|
|
11
|
+
export declare function parseRequestUrl(req: IncomingMessage, fallbackHost: string, fallbackPort: number): URL;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { createHmrBridge, type HmrBridge, type HmrBridgeOptions } from './hmr-bridge.ts';
|
|
2
|
+
export { type RnDevServerHandle, serveRn, type ServeRnExtras } from './serve.ts';
|
|
3
|
+
export { type CliServerApi, type CliWebsocketEndpoint, loadCliServerApi, type LoadCliServerApiOptions, } from './middleware/cli-server-api.ts';
|
|
4
|
+
export { type DevMiddleware, loadDevMiddleware, type LoadDevMiddlewareOptions, } from './middleware/dev-middleware.ts';
|
|
5
|
+
export { createBaseMiddleware, createDevHttpServer, type DevHttpServerDeps, type DevHttpServerHandle, } from './http-server.ts';
|
|
6
|
+
export { parseRequestUrl, readJsonBody, sendJson, sendText } from './http-utils.ts';
|
|
7
|
+
export type { CustomizeFrame, RnDevServerOptions, RnDevServerOptionsInput } from './options.ts';
|
|
8
|
+
export { buildRnDevServerOptions } from './options.ts';
|
|
9
|
+
export { colors, formatLogBadge, logBundle, logError, logInfo, logWarn, printZntcRnBanner, } from './logger.ts';
|
|
10
|
+
export { createPlatformState, createPlatformStateRegistry, getCachedSourceMap, type PlatformState, type PlatformStateCallbacks, type PlatformStateRegistry, waitForBuild, } from './platform-state.ts';
|
|
11
|
+
export { type AssetResolverOptions, handleAssetRequest, isAssetRoute, resolveAssetPath, } from './routes/assets.ts';
|
|
12
|
+
export { handleIndexPage, isIndexRoute } from './routes/index-page.ts';
|
|
13
|
+
export { handleBundleRequest, handleHmrMapRequest, handleMapRequest, isBundleRoute, isHmrMapRoute, isMapRoute, } from './routes/bundle.ts';
|
|
14
|
+
export { handleSymbolicateRequest, isSymbolicateRoute } from './routes/symbolicate.ts';
|
|
15
|
+
export { postProcessSourceMap, type SourcemapPathOptions } from './sourcemap.ts';
|
|
16
|
+
export { setupTerminalActions, type TerminalActionsCallbacks, type TerminalActionsOptions, } from './terminal-actions.ts';
|
|
17
|
+
export { applyCustomizeFrame, createSourceMapConsumer, extractCodeFrame, normalizeFrame, symbolicateFrame, type SymbolicateCodeFrame, type SymbolicateRequest, type SymbolicateResponse, } from './symbolicate-source.ts';
|
|
18
|
+
export type { Broadcast, FrameInfo, Middleware, MiddlewareEnhanceContext } from './types.ts';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export declare const colors: {
|
|
2
|
+
readonly reset: "\u001B[0m";
|
|
3
|
+
readonly bold: "\u001B[1m";
|
|
4
|
+
readonly dim: "\u001B[2m";
|
|
5
|
+
readonly inverse: "\u001B[7m";
|
|
6
|
+
readonly white: "\u001B[37m";
|
|
7
|
+
readonly gray: "\u001B[90m";
|
|
8
|
+
readonly red: "\u001B[31m";
|
|
9
|
+
readonly green: "\u001B[32m";
|
|
10
|
+
readonly yellow: "\u001B[33m";
|
|
11
|
+
readonly blue: "\u001B[34m";
|
|
12
|
+
readonly magenta: "\u001B[35m";
|
|
13
|
+
readonly cyan: "\u001B[36m";
|
|
14
|
+
readonly brightYellow: "\u001B[93m";
|
|
15
|
+
readonly brightRed: "\u001B[91m";
|
|
16
|
+
};
|
|
17
|
+
/** Metro 호환 ` INFO ` cyan inverse bold badge. */
|
|
18
|
+
export declare function logInfo(...args: unknown[]): void;
|
|
19
|
+
export declare function logWarn(...args: unknown[]): void;
|
|
20
|
+
export declare function logError(...args: unknown[]): void;
|
|
21
|
+
/**
|
|
22
|
+
* RN runtime 의 console.log 를 dev server 터미널로 forward 시 사용 — Metro 호환
|
|
23
|
+
* level 별 색상 INVERSE BOLD badge. error=red / warn=yellow / debug=magenta /
|
|
24
|
+
* info=cyan / log=white. bungae graph-bundler/utils.ts 패턴 동등.
|
|
25
|
+
*/
|
|
26
|
+
export declare function formatLogBadge(level: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Metro `TerminalReporter._getBundleStatusMessage` 호환 BUNDLE 상태 라인.
|
|
29
|
+
* `done` 녹색 / `failed` 빨강 / `request` 노랑.
|
|
30
|
+
*/
|
|
31
|
+
export declare function logBundle(phase: 'done' | 'failed' | 'request', platform: string, subject: string, detail?: string): void;
|
|
32
|
+
export declare const ZNTC_ASCII: readonly ["▀▀▀▀▀▀▀▀", "▀▀▀▀▀▀▀▀▀▀▀▀", "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀", "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀", "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀"];
|
|
33
|
+
export declare const ZNTC_GRADIENT: readonly string[];
|
|
34
|
+
/** ZNTC RN dev server 시작 banner — ASCII 로고 + 그라디언트 + 박스. */
|
|
35
|
+
export declare function printZntcRnBanner(version?: string): void;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { IncomingMessage } from 'node:http';
|
|
2
|
+
import type { Duplex } from 'node:stream';
|
|
3
|
+
import type { Broadcast } from '../types.ts';
|
|
4
|
+
export interface CliWebsocketEndpoint {
|
|
5
|
+
handleUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer, callback: (ws: unknown) => void): void;
|
|
6
|
+
emit(event: string, ws: unknown, req: IncomingMessage): void;
|
|
7
|
+
}
|
|
8
|
+
export interface CliServerApi {
|
|
9
|
+
/** ws path → endpoint. /message, /events, /debugger-proxy 등. */
|
|
10
|
+
websocketEndpoints: Record<string, CliWebsocketEndpoint>;
|
|
11
|
+
/** 모든 ws client 에 broadcast — RN runtime 의 `/reload` / `/devmenu` 메시지. */
|
|
12
|
+
broadcast: Broadcast;
|
|
13
|
+
}
|
|
14
|
+
export interface LoadCliServerApiOptions {
|
|
15
|
+
port: number;
|
|
16
|
+
host: string;
|
|
17
|
+
/**
|
|
18
|
+
* peer dependency resolve base — 사용자 프로젝트 root. cli-server-api 가
|
|
19
|
+
* `@zntc/react-native/node_modules` 가 아니라 caller (예: `examples/react-native-bare`)
|
|
20
|
+
* 의 node_modules 에 설치된 경우 dynamic import 가 못 찾는 문제 회피용.
|
|
21
|
+
* 미지정 시 `process.cwd()`.
|
|
22
|
+
*/
|
|
23
|
+
projectRoot?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function loadCliServerApi(options: LoadCliServerApiOptions): Promise<CliServerApi | null>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { Duplex } from 'node:stream';
|
|
3
|
+
export interface DevMiddleware {
|
|
4
|
+
middleware: (req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => void;
|
|
5
|
+
websocketEndpoints: Record<string, {
|
|
6
|
+
handleUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer, callback: (ws: unknown) => void): void;
|
|
7
|
+
emit(event: string, ws: unknown, req: IncomingMessage): void;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Expo 프로젝트는 Rozenite가 @expo/cli 기준의 @react-native/dev-middleware
|
|
12
|
+
* instance를 monkey-patch한다. 같은 module instance를 로드해야 RN DevTools
|
|
13
|
+
* frontend URL 패치가 적용되므로 expo → @expo/cli → react-native CLI chain
|
|
14
|
+
* 순서로 resolve. fallback 으로 project 직접 / zntc 자기.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveDevMiddlewarePath(projectRoot: string): string | null;
|
|
17
|
+
export interface LoadDevMiddlewareOptions {
|
|
18
|
+
port: number;
|
|
19
|
+
projectRoot: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* `@react-native/dev-middleware` 가 설치돼있으면 DevMiddleware instance,
|
|
23
|
+
* 아니면 null. errors swallow + console.warn (caller 가 dev server 띄우는 데
|
|
24
|
+
* 영향 없도록).
|
|
25
|
+
*/
|
|
26
|
+
export declare function loadDevMiddleware(options: LoadDevMiddlewareOptions): Promise<DevMiddleware | null>;
|
|
27
|
+
export declare const DEV_MIDDLEWARE_PATH_PREFIXES: string[];
|
|
28
|
+
/**
|
|
29
|
+
* dev-middleware path prefix 의 정확 경계 매칭. `/jsonbomb` 같은 우연한
|
|
30
|
+
* substring 일치를 막기 위해 정확한 path 또는 슬래시 경계 + tail 만 허용.
|
|
31
|
+
* bungae Server.js 의 prefix 매칭과 동일 패턴 (#2605 audit).
|
|
32
|
+
*/
|
|
33
|
+
export declare function isDevMiddlewareRoute(pathname: string): boolean;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RnBundleInput } from '../preset.ts';
|
|
2
|
+
import type { FrameInfo, Middleware, MiddlewareEnhanceContext } from './types.ts';
|
|
3
|
+
/** customizeFrame `collapse:true` → DevTools 에서 frame 숨김. caller 가 try/catch 로 swallow. */
|
|
4
|
+
export type CustomizeFrame = (frame: FrameInfo) => Promise<{
|
|
5
|
+
collapse?: boolean;
|
|
6
|
+
} | void>;
|
|
7
|
+
export interface RnDevServerOptions {
|
|
8
|
+
bundle: RnBundleInput;
|
|
9
|
+
port: number;
|
|
10
|
+
host: string;
|
|
11
|
+
/** Asset resolution 의 fallback (monorepo / pnpm / bun 의 .bun 디렉토리 등). */
|
|
12
|
+
nodeModulesPaths: readonly string[];
|
|
13
|
+
enhanceMiddleware?: (mw: Middleware, ctx: MiddlewareEnhanceContext) => Middleware;
|
|
14
|
+
/**
|
|
15
|
+
* Request URL 을 routing 전에 rewrite (Metro 호환). Argument 는 jsc-safe URL
|
|
16
|
+
* normalize 가 적용된 **full URL** (path + query). 반환값은 다시 normalize 후
|
|
17
|
+
* `req.url` 에 set. iOS/Hermes 의 jsc-safe URL 재요청을 정상 routing 하려면
|
|
18
|
+
* 미설정해도 OK — 미설정 시 normalize 만 적용.
|
|
19
|
+
*/
|
|
20
|
+
rewriteRequestUrl?: (url: string) => string;
|
|
21
|
+
symbolicator?: {
|
|
22
|
+
customizeFrame?: CustomizeFrame;
|
|
23
|
+
};
|
|
24
|
+
terminalActions: boolean;
|
|
25
|
+
hmr: boolean;
|
|
26
|
+
}
|
|
27
|
+
export type RnDevServerOptionsInput = {
|
|
28
|
+
bundle: RnBundleInput;
|
|
29
|
+
} & Partial<Omit<RnDevServerOptions, 'bundle'>>;
|
|
30
|
+
export declare function buildRnDevServerOptions(input: RnDevServerOptionsInput): RnDevServerOptions;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { WatchHandle, WatchReadyEvent, WatchRebuildEvent } from '@zntc/core';
|
|
2
|
+
import type { RnDevServerOptions } from './options.ts';
|
|
3
|
+
export interface PlatformState {
|
|
4
|
+
readonly platform: 'ios' | 'android';
|
|
5
|
+
readonly outputDir: string;
|
|
6
|
+
readonly outputPath: string;
|
|
7
|
+
handle: WatchHandle;
|
|
8
|
+
bundle: string | null;
|
|
9
|
+
bundleStale: boolean;
|
|
10
|
+
refreshBundle: () => Promise<void>;
|
|
11
|
+
/** rebuild 마다 invalidate. 같은 build 안에서 여러 sourcemap 요청 시 재사용. */
|
|
12
|
+
sourceMapCache: string | null;
|
|
13
|
+
buildError: string | null;
|
|
14
|
+
fileCount: number;
|
|
15
|
+
lastRebuildTime: number;
|
|
16
|
+
}
|
|
17
|
+
/** sourcemap lazy fetch + memoize. cache miss 시 handle 에서 build + postProcess. */
|
|
18
|
+
export declare function getCachedSourceMap(state: PlatformState): string | null;
|
|
19
|
+
export interface PlatformStateCallbacks {
|
|
20
|
+
onReady?: (state: PlatformState, event: WatchReadyEvent) => void;
|
|
21
|
+
onRebuild?: (state: PlatformState, event: WatchRebuildEvent) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* platform 별 watch + state 생성. 첫 build 는 비동기 — caller 가
|
|
25
|
+
* `waitForBuild(state)` 로 대기. RN runtime 이 ios+android 동시 요청 시
|
|
26
|
+
* 별도 outputDir 에 격리.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createPlatformState(options: RnDevServerOptions, platform: 'ios' | 'android', callbacks?: PlatformStateCallbacks): PlatformState;
|
|
29
|
+
/** initial build 또는 buildError 가 정해질 때까지 polling. dev server start 시점 1회. */
|
|
30
|
+
export declare function waitForBuild(state: PlatformState, pollIntervalMs?: number): Promise<void>;
|
|
31
|
+
/** 모든 platform 의 watch handle 종료 + outputDir cleanup (caller 책임). */
|
|
32
|
+
export interface PlatformStateRegistry {
|
|
33
|
+
readonly platforms: ReadonlyMap<string, PlatformState>;
|
|
34
|
+
getOrCreate(platform: 'ios' | 'android'): PlatformState;
|
|
35
|
+
stopAll(): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export declare function createPlatformStateRegistry(options: RnDevServerOptions, callbacks?: PlatformStateCallbacks): PlatformStateRegistry;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { PlatformState, PlatformStateRegistry } from '../platform-state.ts';
|
|
2
|
+
/** query param `?platform=ios|android` 검증 후 invalid 면 default. registry 에서 lazy spawn. */
|
|
3
|
+
export declare function resolvePlatform(url: URL, registry: PlatformStateRegistry, defaultPlatform: 'ios' | 'android'): PlatformState;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
export declare function isAssetRoute(pathname: string): boolean;
|
|
3
|
+
export interface AssetResolverOptions {
|
|
4
|
+
projectRoot: string;
|
|
5
|
+
nodeModulesPaths: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Metro 호환 multi-strategy resolution. node_modules 경로 안 패키지는
|
|
9
|
+
* hoisted/scoped/pnpm/bun/non-hoisted/monorepo/require.resolve 7단계로 시도.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveAssetPath(urlPathname: string, opts: AssetResolverOptions): string | null;
|
|
12
|
+
export declare function handleAssetRequest(_req: IncomingMessage, res: ServerResponse, url: URL, opts: AssetResolverOptions): Promise<void>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import { type PlatformStateRegistry } from '../platform-state.ts';
|
|
3
|
+
export declare function isBundleRoute(pathname: string): boolean;
|
|
4
|
+
export declare function isMapRoute(pathname: string): boolean;
|
|
5
|
+
export declare function isHmrMapRoute(pathname: string): boolean;
|
|
6
|
+
export declare function handleBundleRequest(req: IncomingMessage, res: ServerResponse, url: URL, registry: PlatformStateRegistry, defaultPlatform: 'ios' | 'android', projectRoot: string, port: number): Promise<void>;
|
|
7
|
+
export declare function handleMapRequest(_req: IncomingMessage, res: ServerResponse, url: URL, registry: PlatformStateRegistry, defaultPlatform: 'ios' | 'android'): void;
|
|
8
|
+
export declare function handleHmrMapRequest(_req: IncomingMessage, res: ServerResponse, url: URL, registry: PlatformStateRegistry, defaultPlatform: 'ios' | 'android'): void;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { Broadcast } from '../types.ts';
|
|
3
|
+
export declare function isDevMenuRoute(pathname: string): boolean;
|
|
4
|
+
export declare function handleDevMenu(_req: IncomingMessage, res: ServerResponse, broadcast: Broadcast): void;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
|
+
export declare function isOpenUrlRoute(pathname: string, method: string | undefined): boolean;
|
|
4
|
+
export declare function handleOpenUrl(req: IncomingMessage, res: ServerResponse, spawner?: typeof spawn, platform?: NodeJS.Platform): Promise<void>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { Broadcast } from '../types.ts';
|
|
3
|
+
export declare function isReloadRoute(pathname: string): boolean;
|
|
4
|
+
export declare function handleReload(_req: IncomingMessage, res: ServerResponse, broadcast: Broadcast): void;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { CustomizeFrame } from '../options.ts';
|
|
3
|
+
import { type PlatformStateRegistry } from '../platform-state.ts';
|
|
4
|
+
export declare function isSymbolicateRoute(pathname: string, method: string | undefined): boolean;
|
|
5
|
+
export declare function handleSymbolicateRequest(req: IncomingMessage, res: ServerResponse, url: URL, registry: PlatformStateRegistry, defaultPlatform: 'ios' | 'android', projectRoot: string, customizeFrame: CustomizeFrame | undefined): Promise<void>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type HmrBridge } from './hmr-bridge.ts';
|
|
2
|
+
import type { RnDevServerOptions } from './options.ts';
|
|
3
|
+
import { type PlatformStateRegistry } from './platform-state.ts';
|
|
4
|
+
export interface RnDevServerHandle {
|
|
5
|
+
readonly url: string;
|
|
6
|
+
readonly port: number;
|
|
7
|
+
readonly hmrBridge?: HmrBridge;
|
|
8
|
+
readonly platforms: PlatformStateRegistry;
|
|
9
|
+
stop(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* dev server lifecycle 시작. 첫 platform 의 initial build 까지 대기 후 handle
|
|
13
|
+
* 반환. 종료는 `handle.stop()` — http server close + watch handles stop +
|
|
14
|
+
* terminal raw mode 복원 순서로 graceful.
|
|
15
|
+
*/
|
|
16
|
+
export interface ServeRnExtras {
|
|
17
|
+
/** package version — banner 에 표시. */
|
|
18
|
+
version?: string;
|
|
19
|
+
/** banner / startup log 출력 안 함 (test 환경 등). default false. */
|
|
20
|
+
silent?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* SIGINT/SIGTERM listener 등록 + shutdown 메시지. CLI 사용 시 default true,
|
|
23
|
+
* embed 사용 시 caller 가 직접 lifecycle 관리하면 false. default true.
|
|
24
|
+
*/
|
|
25
|
+
installSignalHandlers?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare function serveRn(options: RnDevServerOptions, extras?: ServeRnExtras): Promise<RnDevServerHandle>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface SourcemapPathOptions {
|
|
2
|
+
/** Metro `sourcemapSourcesRoot` — sourcemap JSON 의 sourceRoot field. */
|
|
3
|
+
sourceRoot?: string;
|
|
4
|
+
/** Metro `sourcemapUseAbsolutePath` — sources 의 path 를 절대화. virtual module skip. */
|
|
5
|
+
useAbsolutePath?: boolean;
|
|
6
|
+
/** projectRoot — useAbsolutePath 시 base. 미설정 시 process.cwd(). */
|
|
7
|
+
projectRoot?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* sourcemap 후처리 — DevTools `x_google_ignoreList` 확장 + (옵션 시)
|
|
11
|
+
* `sourceRoot` / sources 절대화. JSON round-trip 1회로 모든 변환을 한 패스.
|
|
12
|
+
*
|
|
13
|
+
* 잘못된 JSON 또는 version != 3 이면 rawJson 반환 (caller 가 빈 응답 회피).
|
|
14
|
+
*/
|
|
15
|
+
export declare function postProcessSourceMap(rawJson: string, pathOpts?: SourcemapPathOptions): string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { CustomizeFrame } from './options.ts';
|
|
2
|
+
import type { FrameInfo } from './types.ts';
|
|
3
|
+
export interface SymbolicateRequest {
|
|
4
|
+
stack: Array<Partial<FrameInfo>>;
|
|
5
|
+
}
|
|
6
|
+
export interface SymbolicateCodeFrame {
|
|
7
|
+
content: string;
|
|
8
|
+
location: {
|
|
9
|
+
row: number;
|
|
10
|
+
column: number;
|
|
11
|
+
};
|
|
12
|
+
fileName: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SymbolicateResponse {
|
|
15
|
+
stack: Array<FrameInfo & {
|
|
16
|
+
collapse?: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
codeFrame: SymbolicateCodeFrame | null;
|
|
19
|
+
}
|
|
20
|
+
interface SourceMapConsumerLike {
|
|
21
|
+
originalPositionFor(input: {
|
|
22
|
+
line: number;
|
|
23
|
+
column: number;
|
|
24
|
+
}): {
|
|
25
|
+
source: string | null;
|
|
26
|
+
line: number | null;
|
|
27
|
+
column: number | null;
|
|
28
|
+
name: string | null;
|
|
29
|
+
};
|
|
30
|
+
destroy?(): void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* sourceMap JSON → SourceMapConsumer. source-map@^0.7 의 SourceMapConsumer 는
|
|
34
|
+
* Promise<consumer>. 호출자가 try/finally 로 destroy 호출.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createSourceMapConsumer(sourceMapJson: string): Promise<SourceMapConsumerLike | null>;
|
|
37
|
+
/** Partial frame → 모든 필드가 채워진 FrameInfo (null fallback). */
|
|
38
|
+
export declare function normalizeFrame(frame: Partial<FrameInfo>): FrameInfo;
|
|
39
|
+
/** 단일 frame 역매핑. 매핑 실패 시 frame 그대로 (Metro 호환 — DevTools 가 fallback). */
|
|
40
|
+
export declare function symbolicateFrame(consumer: SourceMapConsumerLike, frame: Partial<FrameInfo>, projectRoot: string): FrameInfo;
|
|
41
|
+
/**
|
|
42
|
+
* frame 의 lineNumber 주변 ±2 줄 발췌 — RN runtime / DevTools 의 LogBox 가 보여줌.
|
|
43
|
+
* `.bundle` 경로는 skip — bundled module 은 readable 한 source 가 아님.
|
|
44
|
+
*/
|
|
45
|
+
export declare function extractCodeFrame(frames: ReadonlyArray<FrameInfo & {
|
|
46
|
+
collapse?: boolean;
|
|
47
|
+
}>): Promise<SymbolicateCodeFrame | null>;
|
|
48
|
+
/**
|
|
49
|
+
* customizeFrame 호출 후 collapse 적용. errors are non-fatal (Metro parity).
|
|
50
|
+
*/
|
|
51
|
+
export declare function applyCustomizeFrame(frame: FrameInfo, customizeFrame: CustomizeFrame | undefined): Promise<FrameInfo & {
|
|
52
|
+
collapse?: boolean;
|
|
53
|
+
}>;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface TerminalActionsCallbacks {
|
|
2
|
+
/** `r` — RN runtime reload broadcast. */
|
|
3
|
+
onReload(): void;
|
|
4
|
+
/** `d` — Dev menu broadcast. */
|
|
5
|
+
onDevMenu(): void;
|
|
6
|
+
/** `j` — open DevTools (POST /open-debugger). */
|
|
7
|
+
onOpenDevTools(): void;
|
|
8
|
+
/** `c` — clear cache (per-platform state.bundle null 처리 등). */
|
|
9
|
+
onClearCache(): void;
|
|
10
|
+
/**
|
|
11
|
+
* `v` — RN runtime 의 console.log forwarding mute/unmute. 새 상태 반환 (true=ON,
|
|
12
|
+
* false=OFF) — INFO 피드백 메시지에 사용.
|
|
13
|
+
*/
|
|
14
|
+
onToggleLogs(): boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface TerminalActionsOptions {
|
|
17
|
+
/** false 면 listener 등록 안 하고 no-op cleanup. */
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
/** TTY 가 아니면 listener 등록 skip — CI / pipe 환경 호환. */
|
|
20
|
+
stdin?: NodeJS.ReadStream;
|
|
21
|
+
/** 단축키 list 출력 callback (`?`). 미지정 시 INFO badge default. */
|
|
22
|
+
printShortcuts?(): void;
|
|
23
|
+
}
|
|
24
|
+
/** `?` 응답 — INFO badge + 5칸 들여쓰기 + 앞뒤 빈 줄. */
|
|
25
|
+
export declare function printDefaultShortcuts(): void;
|
|
26
|
+
/**
|
|
27
|
+
* 터미널 raw mode + keypress listener. 반환된 cleanup 호출 시 raw mode 해제 +
|
|
28
|
+
* listener 제거. enabled=false 또는 stdin 비-TTY 시 no-op cleanup.
|
|
29
|
+
*
|
|
30
|
+
* Ctrl+C / Ctrl+D 는 raw mode 에서 자동 SIGINT 안 가서 직접 process.kill 처리.
|
|
31
|
+
*/
|
|
32
|
+
export declare function setupTerminalActions(callbacks: TerminalActionsCallbacks, options?: TerminalActionsOptions): () => void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IncomingMessage, Server, ServerResponse } from 'node:http';
|
|
2
|
+
/** Connect-style middleware (Metro / cli-server-api 호환). */
|
|
3
|
+
export type Middleware = (req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => void;
|
|
4
|
+
/** RN runtime stack frame (metro `IntermediateStackFrame` 와 structural compat). */
|
|
5
|
+
export interface FrameInfo {
|
|
6
|
+
file: string | null;
|
|
7
|
+
methodName: string | null;
|
|
8
|
+
lineNumber: number | null;
|
|
9
|
+
column: number | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* enhanceMiddleware hook 의 ctx. `httpServer` 는 `listen()` 전 instance — `.on("upgrade")`
|
|
13
|
+
* 등 event 등록 용도. lifecycle (close / connection limits) 은 host (serveRn) 책임.
|
|
14
|
+
*/
|
|
15
|
+
export interface MiddlewareEnhanceContext {
|
|
16
|
+
readonly httpServer: Server;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* WS broadcast — cli-server-api 의 `messageSocketEndpoint.broadcast(method, params)` 와
|
|
20
|
+
* 동일 시그니처. PR #G 가 zero-mapping wire.
|
|
21
|
+
*/
|
|
22
|
+
export type Broadcast = (method: string, params?: Record<string, unknown>) => void;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { HMR_RN_MSG, type HmrRnErrorMessage, type HmrRnLogMessage, type HmrRnMessage, type HmrRnMessageType, type HmrRnReloadMessage, type HmrRnUpdateDoneMessage, type HmrRnUpdateMessage, type HmrRnUpdateModule, type HmrRnUpdateStartMessage, } from '@zntc/server';
|
|
2
|
+
export { type AssetResolverOptions, type Broadcast, buildRnDevServerOptions, createBaseMiddleware, createDevHttpServer, createHmrBridge, createPlatformState, type CliServerApi, type CliWebsocketEndpoint, type DevMiddleware, loadCliServerApi, loadDevMiddleware, type LoadCliServerApiOptions, type LoadDevMiddlewareOptions, createPlatformStateRegistry, type CustomizeFrame, type DevHttpServerDeps, type DevHttpServerHandle, type FrameInfo, getCachedSourceMap, type HmrBridge, type HmrBridgeOptions, applyCustomizeFrame, createSourceMapConsumer, extractCodeFrame, handleAssetRequest, handleBundleRequest, handleHmrMapRequest, handleIndexPage, handleMapRequest, handleSymbolicateRequest, isIndexRoute, isAssetRoute, isBundleRoute, isHmrMapRoute, isMapRoute, isSymbolicateRoute, normalizeFrame, symbolicateFrame, type SymbolicateCodeFrame, type SymbolicateRequest, type SymbolicateResponse, type Middleware, type MiddlewareEnhanceContext, type PlatformState, type PlatformStateCallbacks, type PlatformStateRegistry, colors, formatLogBadge, logBundle, logError, logInfo, logWarn, postProcessSourceMap, type SourcemapPathOptions, printZntcRnBanner, resolveAssetPath, type ServeRnExtras, serveRn, setupTerminalActions, type TerminalActionsCallbacks, type TerminalActionsOptions, type RnDevServerHandle, type RnDevServerOptions, type RnDevServerOptionsInput, waitForBuild, } from './dev-server/index.ts';
|
|
3
|
+
export { createMetroHmrAdapter, type MetroHmrAdapter } from './metro-hmr-adapter.ts';
|
|
4
|
+
export type { CustomResolver, MetroPlatform, Resolution, ResolutionContext, } from './metro-resolver-types.ts';
|
|
5
|
+
export { createAssetPlugin } from './plugins/asset.ts';
|
|
6
|
+
export { createBabelPlugin, createBabelTransformer, detectCustomPlugins, isZntcNativePlugin, ZNTC_NATIVE_PLUGIN_PATTERNS, } from './plugins/babel.ts';
|
|
7
|
+
export { CODEGEN_NATIVE_COMPONENT_MARKER, createCodegenPlugin, createCodegenTransformer, } from './plugins/codegen.ts';
|
|
8
|
+
export { escapeRegex } from './plugins/escape-regex.ts';
|
|
9
|
+
export { createMetroResolveRequestPlugin, type MetroResolveRequestOptions, } from './plugins/metro-resolve-request.ts';
|
|
10
|
+
export { createRequireContextPlugin } from './plugins/require-context.ts';
|
|
11
|
+
export { createStyledComponentsNativePlugin, disableStyledComponentsNativeDomProbe, STYLED_COMPONENTS_NATIVE_PATH_RE, } from './plugins/styled-components-native.ts';
|
|
12
|
+
export type { PluginConfig } from './plugins/types.ts';
|
|
13
|
+
export { buildRnBundleOptions, bundleRn, DEFAULT_ASSET_EXTS, type RnBundleInput, type RnWatchInput, watchRn, } from './preset.ts';
|
|
14
|
+
export { resolveRnPolyfills, RN_GLOBAL_IDENTIFIERS, tryResolve } from './rn-constants.ts';
|
|
15
|
+
export { HMR_CLIENT_SUFFIX, ZNTC_HMR_CLIENT_CODE } from './runtime-loader.ts';
|
|
16
|
+
export { detectExpo, WINTER_POLYFILL_WARNING_PATTERN, withExpo, type ZntcRnExpoConfig, } from './withExpo.ts';
|