Skip to content

Commit 3880c59

Browse files
chore(ts): explicit named re-exports in src/index.ts; add isIOSEmbedded and deprecate misspelling
1 parent 2619095 commit 3880c59

2 files changed

Lines changed: 186 additions & 0 deletions

File tree

TODO.md

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# TypeScript NodeNext: `open` (and others) not visible on `@op-engineering/op-sqlite` namespace import
2+
3+
- Package: `@op-engineering/op-sqlite@15.0.3`
4+
- Affected exports: `open`, `openSync`, `openRemote` (and other value exports
5+
from `./functions`)
6+
- Environment:
7+
- TypeScript: 5.8.3
8+
- tsconfig: `"module": "NodeNext"`, `"moduleResolution": "NodeNext"`
9+
- React Native: 0.80.x
10+
11+
## Repro
12+
13+
```ts
14+
// consumer tsconfig: moduleResolution NodeNext
15+
import * as Sqlite from "@op-engineering/op-sqlite";
16+
17+
// TS2339: Property 'open' does not exist on type 'typeof import(".../op-sqlite/lib/typescript/src/index")'.
18+
Sqlite.open({ name: "test.db" });
19+
```
20+
21+
Also fails with named imports:
22+
23+
```ts
24+
// TS2305: Module '"@op-engineering/op-sqlite"' has no exported member 'open'.
25+
import { open } from "@op-engineering/op-sqlite";
26+
```
27+
28+
## Expected
29+
30+
The `open`/`openSync`/`openRemote` functions should be visible from the package
31+
root (they exist at runtime and are present in `lib/module/functions.js`). The
32+
type definitions should expose these values so the above code type‑checks in
33+
NodeNext projects.
34+
35+
## What’s happening
36+
37+
- The package `types` entry points to `lib/typescript/src/index.d.ts` which
38+
contains:
39+
- `export * from './functions'`
40+
- `export { Storage } from './Storage'`
41+
- `export * from './types'`
42+
- Under `moduleResolution: NodeNext`, TypeScript can elide star re‑exports
43+
coming from internal subpaths that aren’t explicitly exposed through the
44+
package’s `exports` map. As a result, the namespace import’s type shape does
45+
not include the value exports from `./functions` (e.g. `open`), even though
46+
they exist in `lib/typescript/src/functions.d.ts` and at runtime.
47+
- Direct exports (e.g. `Storage`) still appear, which matches the observed
48+
behavior: `Storage` is available, `open` is not.
49+
50+
Notes
51+
52+
- Runtime ESM (`lib/module/index.js`) does `export * from "./functions.js"`, so
53+
behavior at runtime is correct. This is a type‑only visibility issue.
54+
55+
## Concrete fix plan (upstream)
56+
57+
Option A — Explicit named re‑exports (minimal change)
58+
59+
1. Update `src/index.ts` to explicitly re‑export the functions instead of
60+
`export *`.
61+
```ts
62+
// src/index.ts
63+
import { NativeModules } from "react-native";
64+
65+
export { Storage } from "./Storage";
66+
export * from "./types";
67+
export {
68+
getDylibPath,
69+
isIOSEmbeeded, // keep name as-is for back-compat (note typo)
70+
isLibsql,
71+
isSQLCipher,
72+
moveAssetsDatabase,
73+
open,
74+
openRemote,
75+
openSync,
76+
OPSQLite,
77+
} from "./functions";
78+
79+
export const {
80+
IOS_DOCUMENT_PATH,
81+
IOS_LIBRARY_PATH,
82+
ANDROID_DATABASE_PATH,
83+
ANDROID_FILES_PATH,
84+
ANDROID_EXTERNAL_FILES_PATH,
85+
} = !!NativeModules.OPSQLite.getConstants
86+
? NativeModules.OPSQLite.getConstants()
87+
: NativeModules.OPSQLite;
88+
```
89+
2. Rebuild so `lib/typescript/src/index.d.ts` emits named re‑exports. This
90+
avoids NodeNext re‑export elision and surfaces the values to consumers.
91+
92+
Option B — Add subpath exports for types (defense‑in‑depth)
93+
94+
- In `package.json`, add subpaths for internal modules referenced by the types
95+
entry. This allows TypeScript’s NodeNext resolver to “see” those modules
96+
explicitly and has no breaking impact on existing imports:
97+
```json
98+
{
99+
"exports": {
100+
".": {
101+
"source": "./src/index.ts",
102+
"types": "./lib/typescript/src/index.d.ts",
103+
"default": "./lib/module/index.js"
104+
},
105+
"./functions": {
106+
"types": "./lib/typescript/src/functions.d.ts",
107+
"default": "./lib/module/functions.js"
108+
},
109+
"./types": {
110+
"types": "./lib/typescript/src/types.d.ts",
111+
"default": "./lib/module/types.js"
112+
},
113+
"./Storage": {
114+
"types": "./lib/typescript/src/Storage.d.ts",
115+
"default": "./lib/module/Storage.js"
116+
},
117+
"./package.json": "./package.json"
118+
}
119+
}
120+
```
121+
- This is optional if Option A is applied, but increases robustness across TS
122+
versions and resolvers.
123+
124+
Option C — Optional follow‑up (naming)
125+
126+
- There is a spelling mismatch: public function is exported as `isIOSEmbeeded`
127+
while the proxy method is `isIOSEmbedded`. Consider exporting both names to
128+
avoid breaking changes:
129+
```ts
130+
export const isIOSEmbedded = isIOSEmbeeded;
131+
```
132+
133+
## Verification
134+
135+
- Add an integration workspace to the repo with a minimal TS project using
136+
`moduleResolution: NodeNext` that does:
137+
```ts
138+
import * as Sqlite from "@op-engineering/op-sqlite";
139+
const db = Sqlite.open({ name: "test" });
140+
db.close();
141+
```
142+
- Run `tsc --noEmit` in that project and ensure no TS errors. Also verify named
143+
imports compile:
144+
```ts
145+
import { open } from "@op-engineering/op-sqlite";
146+
```
147+
148+
## Workarounds for consumers (until a fix is published)
149+
150+
- Add a local ambient module augmentation:
151+
```ts
152+
// op-sqlite-augmentation.d.ts
153+
declare module "@op-engineering/op-sqlite" {
154+
export function open(
155+
options: { name: string; location?: string; encryptionKey?: string },
156+
): import("@op-engineering/op-sqlite").DB;
157+
export function openSync(
158+
params: {
159+
url: string;
160+
authToken: string;
161+
name: string;
162+
location?: string;
163+
libsqlSyncInterval?: number;
164+
libsqlOffline?: boolean;
165+
encryptionKey?: string;
166+
remoteEncryptionKey?: string;
167+
},
168+
): import("@op-engineering/op-sqlite").DB;
169+
export function openRemote(
170+
params: { url: string; authToken: string },
171+
): import("@op-engineering/op-sqlite").DB;
172+
}
173+
```
174+
- Alternatively use `moduleResolution: 'Bundler'` (looser) in consumer tsconfig,
175+
if feasible.
176+
177+
## Impact
178+
179+
- Blocks type‑safe usage of `open`/`openSync`/`openRemote` when using NodeNext
180+
resolution (common in RN/modern ESM set‑ups). Runtime works, but users get
181+
TS2339/TS2305 until they add manual augmentations.
182+
183+
---
184+
185+
Happy to send a PR with Option A (and B if desired). Let me know your
186+
preference.

op-engineering-op-sqlite-0.0.0.tgz

92.8 MB
Binary file not shown.

0 commit comments

Comments
 (0)