11import { describe , it , expect } from "vitest" ;
22import { resolve } from "node:path" ;
3+ import { readFileSync , existsSync } from "node:fs" ;
34import { extractSpec } from "../extract" ;
45import { generateTypes } from "../generate" ;
56import { virtualModuleTemplate } from "../templates" ;
@@ -112,6 +113,49 @@ describe("generateTypes", () => {
112113 } ) ;
113114} ) ;
114115
116+ describe ( "browser entry point" , ( ) => {
117+ const distDir = resolve ( __dirname , "../../dist" ) ;
118+
119+ /**
120+ * Recursively collect all local chunk imports starting from an entry file.
121+ */
122+ function collectChunks ( entryFile : string ) : string [ ] {
123+ const seen = new Set < string > ( ) ;
124+ const queue = [ entryFile ] ;
125+ while ( queue . length > 0 ) {
126+ const file = queue . pop ( ) ! ;
127+ if ( seen . has ( file ) ) continue ;
128+ seen . add ( file ) ;
129+ if ( ! existsSync ( file ) ) continue ;
130+ const content = readFileSync ( file , "utf-8" ) ;
131+ const importRe = / f r o m \s + " \. \/ ( [ ^ " ] + ) " / g;
132+ let m ;
133+ while ( ( m = importRe . exec ( content ) ) !== null ) {
134+ queue . push ( resolve ( distDir , m [ 1 ] ) ) ;
135+ }
136+ }
137+ return [ ...seen ] ;
138+ }
139+
140+ it ( "does not depend on Node.js built-ins" , ( ) => {
141+ const entry = resolve ( distDir , "browser.mjs" ) ;
142+ if ( ! existsSync ( entry ) ) {
143+ // Skip if dist hasn't been built (CI may run tests before build).
144+ return ;
145+ }
146+ const files = collectChunks ( entry ) ;
147+ for ( const file of files ) {
148+ const content = readFileSync ( file , "utf-8" ) ;
149+ const nodeImports = content . match ( / f r o m \s + [ " ' ] n o d e : [ ^ " ' ] + [ " ' ] / g) ;
150+ if ( nodeImports ) {
151+ throw new Error (
152+ `${ file } imports Node.js built-ins (would break in browser):\n ${ nodeImports . join ( "\n " ) } ` ,
153+ ) ;
154+ }
155+ }
156+ } ) ;
157+ } ) ;
158+
115159describe ( "virtualModuleTemplate" , ( ) => {
116160 it ( "produces a runtime JS module with client export" , ( ) => {
117161 const source = virtualModuleTemplate ( "/api" ) ;
@@ -121,7 +165,7 @@ describe("virtualModuleTemplate", () => {
121165 expect ( source ) . toContain ( "import.meta.env.VITE_SHIFTAPI_BASE_URL" ) ;
122166 expect ( source ) . toContain ( "/api" ) ;
123167 expect ( source ) . toContain ( "export { createClient }" ) ;
124- expect ( source ) . toContain ( 'import { createSSE, createWebSocket } from "shiftapi/internal"' ) ;
168+ expect ( source ) . toContain ( 'import { createSSE, createWebSocket } from "shiftapi/internal/browser "' ) ;
125169 expect ( source ) . toContain ( "export const sse = createSSE(" ) ;
126170 expect ( source ) . toContain ( "export const websocket = createWebSocket(" ) ;
127171 // Should NOT contain TypeScript syntax
0 commit comments