dtunnel-sdk 1.1.4 → 1.2.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/README.md CHANGED
@@ -10,7 +10,7 @@ npm install dtunnel-sdk
10
10
 
11
11
  ## Inicializar projeto pronto
12
12
 
13
- Crie um projeto novo com template e `build:webview` ja configurado:
13
+ Crie um projeto novo com template e `build:android` ja configurado:
14
14
 
15
15
  ```bash
16
16
  npx dtunnel-sdk init
@@ -30,49 +30,55 @@ Tambem funciona com `npm exec`:
30
30
  npm exec dtunnel-sdk init meu-app --template react-typescript
31
31
  ```
32
32
 
33
- ## Uso rapido
33
+ ## Uso rapido
34
34
 
35
35
  ```ts
36
36
  import DTunnelSDK from 'dtunnel-sdk';
37
37
 
38
- const sdk = new DTunnelSDK({
39
- strict: false,
40
- autoRegisterNativeEvents: true,
41
- });
38
+ const sdk = new DTunnelSDK({
39
+ strict: false,
40
+ autoRegisterNativeEvents: true,
41
+ });
42
42
 
43
43
  sdk.on('vpnState', (event) => {
44
44
  console.log('VPN:', event.payload);
45
- });
46
- ```
47
-
48
- ## Simulador rapido (sem Android)
49
-
50
- ```ts
51
- import DTunnelSDK from 'dtunnel-sdk';
52
- import { installDTunnelSDKSimulator } from 'dtunnel-sdk/simulator';
53
-
54
- const simulator = installDTunnelSDKSimulator();
55
- const sdk = new DTunnelSDK({ strict: false, autoRegisterNativeEvents: true });
56
-
57
- simulator.emit('vpnState', 'CONNECTED');
58
- ```
59
-
60
- Browser puro (sem bundler):
61
-
62
- ```html
63
- <script src="https://cdn.jsdelivr.net/npm/dtunnel-sdk@latest/sdk/dtunnel-sdk.js"></script>
64
- <script src="https://cdn.jsdelivr.net/npm/dtunnel-sdk@latest/sdk/dtunnel-sdk.simulator.js"></script>
65
- ```
66
-
67
- Nota:
68
- - No WebView real, o simulador nao instala por padrao se detectar bridge nativa.
45
+ });
46
+ ```
47
+
48
+ ## Simulador rapido (sem Android)
49
+
50
+ ```ts
51
+ import DTunnelSDK from 'dtunnel-sdk';
52
+ import { installDTunnelSDKSimulator } from 'dtunnel-sdk/simulator';
69
53
 
70
- CDN:
54
+ const simulator = installDTunnelSDKSimulator();
55
+ const sdk = new DTunnelSDK({ strict: false, autoRegisterNativeEvents: true });
56
+
57
+ sdk.on('vpnState', (event) => {
58
+ console.log('VPN:', event.payload);
59
+ });
60
+ simulator.emit('vpnState', 'CONNECTED');
61
+ ```
62
+
63
+ Browser puro (sem bundler):
71
64
 
72
65
  ```html
73
66
  <script src="https://cdn.jsdelivr.net/npm/dtunnel-sdk@latest/sdk/dtunnel-sdk.js"></script>
67
+ <script src="https://cdn.jsdelivr.net/npm/dtunnel-sdk@latest/sdk/dtunnel-sdk.simulator.js"></script>
68
+ <script>
69
+ const sdk = new window.DTunnelSDK({ strict: false, autoRegisterNativeEvents: true });
70
+ const simulator = window.DTunnelSDKSimulator.installDTunnelSDKSimulator();
71
+
72
+ sdk.on('vpnState', (event) => {
73
+ console.log('VPN:', event.payload);
74
+ });
75
+ simulator.emit('vpnState', 'CONNECTED');
76
+ </script>
74
77
  ```
75
78
 
79
+ Nota:
80
+ - No WebView real, o simulador nao instala por padrao se detectar bridge nativa.
81
+
76
82
  ## Documentacao completa
77
83
 
78
84
  Toda a documentacao foi movida para `docs/`:
@@ -87,14 +93,14 @@ Toda a documentacao foi movida para `docs/`:
87
93
 
88
94
  Use apenas `init` para gerar projeto pronto:
89
95
 
90
- ```bash
91
- npx dtunnel-sdk init meu-app --template react-typescript
92
- cd meu-app
93
- npm run build:webview
94
- ```
95
-
96
- O resultado final para o WebView sempre sera:
97
- - `webview/index.html`
96
+ ```bash
97
+ npx dtunnel-sdk init meu-app --template react-typescript
98
+ cd meu-app
99
+ npm run build:android
100
+ ```
101
+
102
+ O resultado final para Android e um arquivo unico:
103
+ - `dist/build.html`
98
104
 
99
105
  ## Demos prontas
100
106
 
@@ -116,6 +122,6 @@ npm run test:typecheck
116
122
  ## Release e publicacao
117
123
 
118
124
  ```bash
119
- npm run release:sdk -- --version X.Y.Z
120
- npm run publish:npm
121
- ```
125
+ npm run release:sdk -- --version X.Y.Z
126
+ npm run release:npm
127
+ ```
@@ -11,6 +11,7 @@ const __dirname = path.dirname(__filename);
11
11
  const ROOT_DIR = path.resolve(__dirname, '..');
12
12
  const TEMPLATES_DIR = path.join(ROOT_DIR, 'templates');
13
13
  const PKG_JSON_PATH = path.join(ROOT_DIR, 'package.json');
14
+ const REQUIRED_GITIGNORE_ENTRIES = ['node_modules', 'dist'];
14
15
 
15
16
  const TEMPLATE_CHOICES = [
16
17
  { id: 'react-typescript', label: 'React + TypeScript (Vite)' },
@@ -258,6 +259,67 @@ async function copyDirRecursive(sourceDir, targetDir) {
258
259
  }
259
260
  }
260
261
 
262
+ async function normalizeIgnoreFiles(targetDir) {
263
+ const entries = await fs.readdir(targetDir, { withFileTypes: true });
264
+
265
+ for (const entry of entries) {
266
+ if (!entry.isDirectory()) continue;
267
+ await normalizeIgnoreFiles(path.join(targetDir, entry.name));
268
+ }
269
+
270
+ const gitignorePath = path.join(targetDir, '.gitignore');
271
+ const npmignorePath = path.join(targetDir, '.npmignore');
272
+ const plainIgnorePath = path.join(targetDir, 'gitignore');
273
+ const hasGitignore = await pathExists(gitignorePath);
274
+
275
+ if (!hasGitignore && (await pathExists(npmignorePath))) {
276
+ await fs.rename(npmignorePath, gitignorePath);
277
+ } else if (!hasGitignore && (await pathExists(plainIgnorePath))) {
278
+ await fs.rename(plainIgnorePath, gitignorePath);
279
+ }
280
+
281
+ if ((await pathExists(gitignorePath)) && (await pathExists(npmignorePath))) {
282
+ await fs.rm(npmignorePath, { force: true });
283
+ }
284
+
285
+ if ((await pathExists(gitignorePath)) && (await pathExists(plainIgnorePath))) {
286
+ await fs.rm(plainIgnorePath, { force: true });
287
+ }
288
+ }
289
+
290
+ async function ensureRootGitignoreDefaults(targetDir) {
291
+ const gitignorePath = path.join(targetDir, '.gitignore');
292
+ const hasGitignore = await pathExists(gitignorePath);
293
+
294
+ if (!hasGitignore) {
295
+ await fs.writeFile(
296
+ gitignorePath,
297
+ `${REQUIRED_GITIGNORE_ENTRIES.join('\n')}\n`,
298
+ 'utf8',
299
+ );
300
+ return;
301
+ }
302
+
303
+ const raw = await fs.readFile(gitignorePath, 'utf8');
304
+ const normalized = raw.replace(/\r\n/g, '\n');
305
+ const existing = new Set(
306
+ normalized
307
+ .split('\n')
308
+ .map((line) => line.trim())
309
+ .filter((line) => line.length > 0),
310
+ );
311
+ const missing = REQUIRED_GITIGNORE_ENTRIES.filter((line) => !existing.has(line));
312
+
313
+ if (missing.length === 0) return;
314
+
315
+ let next = normalized;
316
+ if (next.length > 0 && !next.endsWith('\n')) {
317
+ next += '\n';
318
+ }
319
+ next += `${missing.join('\n')}\n`;
320
+ await fs.writeFile(gitignorePath, next, 'utf8');
321
+ }
322
+
261
323
  function isTextLikeFile(fileName) {
262
324
  if (fileName === '.gitignore') return true;
263
325
  const ext = path.extname(fileName);
@@ -338,16 +400,16 @@ function printNextSteps({
338
400
  }
339
401
 
340
402
  if (template === 'cdn') {
341
- console.log(` ${runScriptCommand(packageManager, 'build:webview')}`);
342
- console.log('\nArquivo final para WebView:');
343
- console.log(` ${path.join(projectName, 'webview', 'index.html')}`);
403
+ console.log(` ${runScriptCommand(packageManager, 'build:android')}`);
404
+ console.log('\nArquivo final para Android (unico):');
405
+ console.log(` ${path.join(projectName, 'dist', 'build.html')}`);
344
406
  return;
345
407
  }
346
408
 
347
409
  console.log(` ${runScriptCommand(packageManager, 'dev')}`);
348
- console.log(` ${runScriptCommand(packageManager, 'build:webview')}`);
349
- console.log('\nArquivo final para WebView:');
350
- console.log(` ${path.join(projectName, 'webview', 'index.html')}`);
410
+ console.log(` ${runScriptCommand(packageManager, 'build:android')}`);
411
+ console.log('\nArquivo final para Android (unico):');
412
+ console.log(` ${path.join(projectName, 'dist', 'build.html')}`);
351
413
  }
352
414
 
353
415
  async function runInit(parsed) {
@@ -402,6 +464,8 @@ async function runInit(parsed) {
402
464
  const targetDir = path.resolve(process.cwd(), projectName);
403
465
  await ensureTargetDirectory(targetDir, parsed.force);
404
466
  await copyDirRecursive(templateDir, targetDir);
467
+ await normalizeIgnoreFiles(targetDir);
468
+ await ensureRootGitignoreDefaults(targetDir);
405
469
 
406
470
  const sdkVersion = await readSdkVersion();
407
471
  await applyReplacements(targetDir, {
@@ -8,7 +8,7 @@ npm install dtunnel-sdk
8
8
 
9
9
  ## Bootstrap de projeto (CLI)
10
10
 
11
- Crie um projeto novo com template e script de WebView pronto:
11
+ Crie um projeto novo com template e script de build para Android pronto:
12
12
 
13
13
  ```bash
14
14
  npx dtunnel-sdk init
@@ -82,21 +82,21 @@ export function App() {
82
82
  </script>
83
83
  ```
84
84
 
85
- ## Regra de WebView: sempre um unico `index.html`
86
-
87
- Para publicar no WebView Android, entregue um arquivo unico com CSS/JS embutidos.
88
-
89
- - Todo projeto criado pelo CLI gera `webview/index.html`.
90
-
91
- Fluxo recomendado:
85
+ ## Build para Android em arquivo unico
86
+
87
+ Para publicar no Android, o artefato final e um unico `dist/build.html`.
88
+
89
+ - Todo projeto criado pelo CLI inclui `npm run build:android`.
90
+
91
+ Fluxo recomendado:
92
92
 
93
93
  ```bash
94
94
  npx dtunnel-sdk init meu-app --template react-typescript
95
95
  cd meu-app
96
- npm run build:webview
97
- ```
98
-
99
- ## Comportamento de erro (`strict`)
96
+ npm run build:android
97
+ ```
98
+
99
+ ## Comportamento de erro (`strict`)
100
100
 
101
101
  - `strict: false` (padrao recomendado para WebView): erros de bridge retornam `null` e disparam evento `error`.
102
102
  - `strict: true`: a chamada lanca `DTunnelBridgeError`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dtunnel-sdk",
3
- "version": "1.1.4",
3
+ "version": "1.2.0",
4
4
  "description": "JavaScript/TypeScript SDK for the DTunnel Android WebView bridge.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -10,13 +10,12 @@
10
10
  "bin": {
11
11
  "dtunnel-sdk": "bin/dtunnel-sdk.mjs"
12
12
  },
13
- "scripts": {
14
- "test": "node --import tsx --test ./tests/*.test.mts",
15
- "test:typecheck": "tsc -p ./tests/tsconfig.json --noEmit",
16
- "publish:npm": "node ./scripts/publish-npm.mjs",
17
- "publish:npm:dry": "node ./scripts/publish-npm.mjs --dry-run --skip-auth",
18
- "release:sdk": "node ./scripts/release-sdk.mjs"
19
- },
13
+ "scripts": {
14
+ "test": "node --import tsx --test ./tests/*.test.mts",
15
+ "test:typecheck": "tsc -p ./tests/tsconfig.json --noEmit",
16
+ "release:npm": "node ./scripts/release-npm.mjs",
17
+ "release:sdk": "node ./scripts/release-sdk.mjs"
18
+ },
20
19
  "exports": {
21
20
  ".": {
22
21
  "types": "./sdk/dtunnel-sdk.d.ts",
package/sdk/README.md CHANGED
@@ -1,60 +1,60 @@
1
1
  # DTunnel SDK (Runtime)
2
2
 
3
- Arquivos do runtime e tipagem:
4
-
5
- - `dtunnel-sdk.js`: build principal (script tag + CommonJS)
6
- - `dtunnel-sdk.mjs`: entrada ESM para bundlers
7
- - `dtunnel-sdk.d.ts`: tipagem TypeScript
8
- - `dtunnel-sdk.simulator.js`: simulador da bridge (`window.Dt...`)
9
- - `dtunnel-sdk.simulator.d.ts`: tipagem TypeScript do simulador
10
- - `dtunnel-sdk.simulator.mjs`: entrada ESM do simulador
3
+ Arquivos do runtime e tipagem:
4
+
5
+ - `dtunnel-sdk.js`: build principal (script tag + CommonJS)
6
+ - `dtunnel-sdk.mjs`: entrada ESM para bundlers
7
+ - `dtunnel-sdk.d.ts`: tipagem TypeScript
8
+ - `dtunnel-sdk.simulator.js`: simulador da bridge (`window.Dt...`)
9
+ - `dtunnel-sdk.simulator.d.ts`: tipagem TypeScript do simulador
10
+ - `dtunnel-sdk.simulator.mjs`: entrada ESM do simulador
11
11
 
12
12
  ## Inicializacao
13
13
 
14
14
  ```ts
15
- import DTunnelSDK from 'dtunnel-sdk';
16
-
17
- const sdk = new DTunnelSDK({
18
- strict: false,
19
- autoRegisterNativeEvents: true,
20
- });
21
- ```
22
-
23
- ## Simulador da bridge no navegador
24
-
25
- ### Uso
26
-
27
- ```ts
28
- import DTunnelSDK from 'dtunnel-sdk';
29
- import { installDTunnelSDKSimulator } from 'dtunnel-sdk/simulator';
30
-
31
- const simulator = installDTunnelSDKSimulator();
32
- const sdk = new DTunnelSDK({ strict: false, autoRegisterNativeEvents: true });
33
-
34
- sdk.main.startVpn(); // usa simulador
35
- simulator.emit('vpnState', 'CONNECTED'); // dispara callback nativo
36
- ```
37
-
38
- ### Regra de WebView real
39
-
40
- Por padrao, `installDTunnelSDKSimulator()` nao instala se detectar bridge nativa no `window` (nao sobrescreve `window.Dt...` no app real).
41
-
42
- ### Script tag (CDN/browser puro)
43
-
44
- ```html
45
- <script src="https://cdn.jsdelivr.net/npm/dtunnel-sdk@latest/sdk/dtunnel-sdk.js"></script>
46
- <script src="https://cdn.jsdelivr.net/npm/dtunnel-sdk@latest/sdk/dtunnel-sdk.simulator.js"></script>
47
- ```
48
-
49
- Depois disso:
50
-
51
- ```html
52
- <script>
53
- const sdk = new window.DTunnelSDK({ strict: false, autoRegisterNativeEvents: true });
54
- const simulator = window.DTunnelSDKSimulator.installDTunnelSDKSimulator();
55
- simulator.emit('vpnState', 'CONNECTED');
56
- </script>
57
- ```
15
+ import DTunnelSDK from 'dtunnel-sdk';
16
+
17
+ const sdk = new DTunnelSDK({
18
+ strict: false,
19
+ autoRegisterNativeEvents: true,
20
+ });
21
+ ```
22
+
23
+ ## Simulador da bridge no navegador
24
+
25
+ ### Uso
26
+
27
+ ```ts
28
+ import DTunnelSDK from 'dtunnel-sdk';
29
+ import { installDTunnelSDKSimulator } from 'dtunnel-sdk/simulator';
30
+
31
+ const simulator = installDTunnelSDKSimulator();
32
+ const sdk = new DTunnelSDK({ strict: false, autoRegisterNativeEvents: true });
33
+
34
+ sdk.main.startVpn(); // usa simulador
35
+ simulator.emit('vpnState', 'CONNECTED'); // dispara callback nativo
36
+ ```
37
+
38
+ ### Regra de WebView real
39
+
40
+ Por padrao, `installDTunnelSDKSimulator()` nao instala se detectar bridge nativa no `window` (nao sobrescreve `window.Dt...` no app real).
41
+
42
+ ### Script tag (CDN/browser puro)
43
+
44
+ ```html
45
+ <script src="https://cdn.jsdelivr.net/npm/dtunnel-sdk@latest/sdk/dtunnel-sdk.js"></script>
46
+ <script src="https://cdn.jsdelivr.net/npm/dtunnel-sdk@latest/sdk/dtunnel-sdk.simulator.js"></script>
47
+ ```
48
+
49
+ Depois disso:
50
+
51
+ ```html
52
+ <script>
53
+ const sdk = new window.DTunnelSDK({ strict: false, autoRegisterNativeEvents: true });
54
+ const simulator = window.DTunnelSDKSimulator.installDTunnelSDKSimulator();
55
+ simulator.emit('vpnState', 'CONNECTED');
56
+ </script>
57
+ ```
58
58
 
59
59
  ## Modulos
60
60
 
@@ -93,12 +93,10 @@ Use `sdk.on('<evento>', handler)` com:
93
93
  - React + TypeScript: `examples/react-typescript`
94
94
  - Guia geral: `examples/README.md`
95
95
 
96
- Regra para WebView:
97
- - entregue sempre um unico `index.html` com CSS/JS embutido.
98
- - nos exemplos TypeScript/React, use `npm run build:webview` para gerar `webview/index.html`.
99
- - atalho na raiz: `npm run examples:webview`.
96
+ Regra para WebView:
97
+ - use `npm run build:android` para gerar `dist/build.html` (arquivo unico).
100
98
 
101
99
  Publicacao npm (raiz do repo):
102
- - scripts de publicacao/release sao cross-platform (Linux, macOS e Windows).
103
- - `npm login`
104
- - `npm run publish:npm`
100
+ - scripts de publicacao/release sao cross-platform (Linux, macOS e Windows).
101
+ - `npm login`
102
+ - `npm run release:npm`
@@ -698,7 +698,7 @@
698
698
  }
699
699
  }
700
700
 
701
- DTunnelSDK.VERSION = '1.1.4';
701
+ DTunnelSDK.VERSION = '1.2.0';
702
702
  DTunnelSDK.BRIDGE_OBJECTS = BRIDGE_OBJECTS;
703
703
  DTunnelSDK.EVENT_DEFINITIONS = EVENT_DEFINITIONS;
704
704
  DTunnelSDK.DTunnelBridgeError = DTunnelBridgeError;
@@ -5,11 +5,11 @@ Projeto pronto para uso com CDN.
5
5
  ## Comandos
6
6
 
7
7
  ```bash
8
- npm run build:webview
8
+ npm run build:android
9
9
  ```
10
10
 
11
11
  Saida:
12
- - `webview/index.html`
12
+ - `dist/build.html`
13
13
 
14
14
  ## Uso
15
15
 
@@ -5,6 +5,6 @@
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "node -e \"console.log('Abra index.html no navegador ou WebView.')\"",
8
- "build:webview": "node ./scripts/copy-webview.mjs"
8
+ "build:android": "node ./scripts/build-android-html.mjs"
9
9
  }
10
- }
10
+ }
@@ -4,10 +4,10 @@ import path from 'node:path';
4
4
 
5
5
  const cwd = process.cwd();
6
6
  const inputPath = path.join(cwd, 'index.html');
7
- const outputPath = path.join(cwd, 'webview', 'index.html');
7
+ const outputPath = path.join(cwd, 'dist', 'build.html');
8
8
 
9
9
  const html = await fs.readFile(inputPath, 'utf8');
10
10
  await fs.mkdir(path.dirname(outputPath), { recursive: true });
11
11
  await fs.writeFile(outputPath, html, 'utf8');
12
12
 
13
- console.log(`[build-webview] Gerado: ${outputPath}`);
13
+ console.log(`[build-android] Gerado: ${outputPath}`);
@@ -1,14 +1,14 @@
1
1
  # DTunnel SDK - Template React + TypeScript
2
2
 
3
- Projeto React + TypeScript (Vite) pronto com `build:webview`.
3
+ Projeto React + TypeScript (Vite) pronto com `build:android`.
4
4
 
5
5
  ## Comandos
6
6
 
7
7
  ```bash
8
8
  npm install
9
9
  npm run dev
10
- npm run build:webview
10
+ npm run build:android
11
11
  ```
12
12
 
13
- Saida:
14
- - `webview/index.html`
13
+ Saida:
14
+ - `dist/build.html` (arquivo unico)
@@ -6,7 +6,7 @@
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "vite build",
9
- "build:webview": "npm run build && node ./scripts/build-webview-html.mjs --dist dist --out webview/index.html",
9
+ "build:android": "npm run build && node ./scripts/build-android-html.mjs --dist dist --out dist/build.html",
10
10
  "preview": "vite preview",
11
11
  "typecheck": "tsc --noEmit"
12
12
  },
@@ -6,7 +6,7 @@ import process from 'node:process';
6
6
  function parseArgs(argv) {
7
7
  const options = {
8
8
  dist: 'dist',
9
- out: 'webview/index.html',
9
+ out: 'dist/build.html',
10
10
  };
11
11
 
12
12
  for (let i = 0; i < argv.length; i += 1) {
@@ -116,6 +116,23 @@ function removeLocalModulePreloads(html) {
116
116
  });
117
117
  }
118
118
 
119
+ async function keepOnlyOutputFile(outputPath) {
120
+ const outputDir = path.dirname(outputPath);
121
+ const entries = await fs.readdir(outputDir, { withFileTypes: true });
122
+
123
+ for (const entry of entries) {
124
+ const entryPath = path.join(outputDir, entry.name);
125
+ if (path.resolve(entryPath) === outputPath) continue;
126
+
127
+ if (entry.isDirectory()) {
128
+ await fs.rm(entryPath, { recursive: true, force: true });
129
+ continue;
130
+ }
131
+
132
+ await fs.rm(entryPath, { force: true });
133
+ }
134
+ }
135
+
119
136
  async function main() {
120
137
  const args = parseArgs(process.argv.slice(2));
121
138
  const cwd = process.cwd();
@@ -126,7 +143,7 @@ async function main() {
126
143
  const outputDir = path.dirname(outputPath);
127
144
 
128
145
  if (!(await fileExists(inputPath))) {
129
- console.error(`[build-html] index nao encontrado: ${inputPath}`);
146
+ console.error(`[build-android] index nao encontrado: ${inputPath}`);
130
147
  process.exit(1);
131
148
  }
132
149
 
@@ -137,11 +154,12 @@ async function main() {
137
154
 
138
155
  await fs.mkdir(outputDir, { recursive: true });
139
156
  await fs.writeFile(outputPath, html, 'utf8');
157
+ await keepOnlyOutputFile(outputPath);
140
158
 
141
- console.log(`[build-html] Gerado: ${outputPath}`);
159
+ console.log(`[build-android] Gerado: ${outputPath}`);
142
160
  }
143
161
 
144
162
  main().catch((error) => {
145
- console.error('[build-html] Falha:', error);
163
+ console.error('[build-android] Falha:', error);
146
164
  process.exit(1);
147
165
  });
@@ -1,14 +1,14 @@
1
1
  # DTunnel SDK - Template TypeScript
2
2
 
3
- Projeto TypeScript (Vite) pronto com `build:webview`.
3
+ Projeto TypeScript (Vite) pronto com `build:android`.
4
4
 
5
5
  ## Comandos
6
6
 
7
7
  ```bash
8
8
  npm install
9
9
  npm run dev
10
- npm run build:webview
10
+ npm run build:android
11
11
  ```
12
12
 
13
- Saida:
14
- - `webview/index.html`
13
+ Saida:
14
+ - `dist/build.html` (arquivo unico)
@@ -6,7 +6,7 @@
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "vite build",
9
- "build:webview": "npm run build && node ./scripts/build-webview-html.mjs --dist dist --out webview/index.html",
9
+ "build:android": "npm run build && node ./scripts/build-android-html.mjs --dist dist --out dist/build.html",
10
10
  "preview": "vite preview",
11
11
  "typecheck": "tsc --noEmit"
12
12
  },
@@ -6,7 +6,7 @@ import process from 'node:process';
6
6
  function parseArgs(argv) {
7
7
  const options = {
8
8
  dist: 'dist',
9
- out: 'webview/index.html',
9
+ out: 'dist/build.html',
10
10
  };
11
11
 
12
12
  for (let i = 0; i < argv.length; i += 1) {
@@ -116,6 +116,23 @@ function removeLocalModulePreloads(html) {
116
116
  });
117
117
  }
118
118
 
119
+ async function keepOnlyOutputFile(outputPath) {
120
+ const outputDir = path.dirname(outputPath);
121
+ const entries = await fs.readdir(outputDir, { withFileTypes: true });
122
+
123
+ for (const entry of entries) {
124
+ const entryPath = path.join(outputDir, entry.name);
125
+ if (path.resolve(entryPath) === outputPath) continue;
126
+
127
+ if (entry.isDirectory()) {
128
+ await fs.rm(entryPath, { recursive: true, force: true });
129
+ continue;
130
+ }
131
+
132
+ await fs.rm(entryPath, { force: true });
133
+ }
134
+ }
135
+
119
136
  async function main() {
120
137
  const args = parseArgs(process.argv.slice(2));
121
138
  const cwd = process.cwd();
@@ -126,7 +143,7 @@ async function main() {
126
143
  const outputDir = path.dirname(outputPath);
127
144
 
128
145
  if (!(await fileExists(inputPath))) {
129
- console.error(`[build-html] index nao encontrado: ${inputPath}`);
146
+ console.error(`[build-android] index nao encontrado: ${inputPath}`);
130
147
  process.exit(1);
131
148
  }
132
149
 
@@ -137,11 +154,12 @@ async function main() {
137
154
 
138
155
  await fs.mkdir(outputDir, { recursive: true });
139
156
  await fs.writeFile(outputPath, html, 'utf8');
157
+ await keepOnlyOutputFile(outputPath);
140
158
 
141
- console.log(`[build-html] Gerado: ${outputPath}`);
159
+ console.log(`[build-android] Gerado: ${outputPath}`);
142
160
  }
143
161
 
144
162
  main().catch((error) => {
145
- console.error('[build-html] Falha:', error);
163
+ console.error('[build-android] Falha:', error);
146
164
  process.exit(1);
147
165
  });