@apexkit/cli 1.0.2 → 1.0.4

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 CHANGED
File without changes
package/README.md CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apexkit/cli",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "The official CLI and developer sync engine for ApexKit",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/index.js CHANGED
@@ -141,7 +141,157 @@ const TRIGGER_DEFINITIONS = [
141
141
  { id: "graphql", name: "graphql (Custom Resolver)", desc: "Dynamic Query/Mutation field resolver for GraphQL schema." }
142
142
  ];
143
143
 
144
- // --- 4. ACCURATE WORKSPACE TYPES & CONFIG GENERATOR ---
144
+ // --- 4. AUTOMATED REMOTE TYPE RESOLUTION & SCANNER ---
145
+ function scanWorkspaceForRemoteUrls() {
146
+ const urls = new Set();
147
+ const dirs = ["./webhooks", "./modules", "./templates"];
148
+ const urlRegex =
149
+ /(?:import|export)\s+(?:[\s\S]*?from\s+)?["'](https?:\/\/[^"']+)["']|import\s*\(\s*["'](https?:\/\/[^"']+)["']\s*\)|@jsxImportSource\s+(https?:\/\/[^\s*]+)/g;
150
+
151
+ dirs.forEach((dir) => {
152
+ if (!fs.existsSync(dir)) return;
153
+ const files = fs.readdirSync(dir, { recursive: true });
154
+ files.forEach((file) => {
155
+ const fullPath = path.join(dir, file);
156
+ if (fs.statSync(fullPath).isFile()) {
157
+ const ext = path.extname(fullPath);
158
+ if ([".js", ".ts", ".jsx", ".tsx", ".html"].includes(ext)) {
159
+ try {
160
+ const content = fs.readFileSync(fullPath, "utf-8");
161
+ let match;
162
+ while ((match = urlRegex.exec(content)) !== null) {
163
+ const url = match[1] || match[2] || match[3];
164
+ if (url) urls.add(url.trim());
165
+ }
166
+ } catch (e) {}
167
+ }
168
+ }
169
+ });
170
+ });
171
+
172
+ return Array.from(urls);
173
+ }
174
+
175
+ async function resolveRemoteTypeUrl(importUrl) {
176
+ try {
177
+ const res = await fetch(importUrl, {
178
+ method: "GET",
179
+ headers: { "User-Agent": "ApexKit-CLI/1.0" },
180
+ redirect: "follow",
181
+ });
182
+
183
+ const dtsHeader = res.headers.get("x-typescript-types");
184
+ if (dtsHeader) {
185
+ return dtsHeader.startsWith("http") ? dtsHeader : new URL(dtsHeader, importUrl).href;
186
+ }
187
+
188
+ if (importUrl.endsWith(".d.ts")) {
189
+ return importUrl;
190
+ }
191
+
192
+ if (importUrl.includes("esm.sh")) {
193
+ const dtsParamUrl = importUrl.includes("?") ? `${importUrl}&dts` : `${importUrl}?dts`;
194
+ const paramRes = await fetch(dtsParamUrl, { method: "HEAD", redirect: "follow" });
195
+ const paramHeader = paramRes.headers.get("x-typescript-types");
196
+ if (paramHeader) {
197
+ return paramHeader.startsWith("http") ? paramHeader : new URL(paramHeader, importUrl).href;
198
+ }
199
+ }
200
+ } catch (e) {}
201
+ return null;
202
+ }
203
+
204
+ /**
205
+ * Recursively fetches a .d.ts file and all relative imports/exports inside it
206
+ */
207
+ async function downloadDtsTree(currentDtsUrl, baseDir, relativeSubpath = "index.d.ts", visited = new Set()) {
208
+ if (visited.has(currentDtsUrl)) return;
209
+ visited.add(currentDtsUrl);
210
+
211
+ const localFilePath = path.join(baseDir, relativeSubpath);
212
+ fs.mkdirSync(path.dirname(localFilePath), { recursive: true });
213
+
214
+ try {
215
+ const res = await fetch(currentDtsUrl, {
216
+ headers: { "User-Agent": "ApexKit-CLI/1.0" },
217
+ redirect: "follow",
218
+ });
219
+ if (!res.ok) return;
220
+
221
+ let content = await res.text();
222
+
223
+ // Regex to locate relative imports or exports like:
224
+ // import { Hono } from './hono.d.ts';
225
+ // export * from './types.d.ts';
226
+ const relImportRegex = /(?:import|export)\s+[\s\S]*?from\s+["'](\.[^"']+)["']/g;
227
+ const relMatches = [];
228
+ let match;
229
+ while ((match = relImportRegex.exec(content)) !== null) {
230
+ relMatches.push(match[1]);
231
+ }
232
+
233
+ // Write file locally
234
+ fs.writeFileSync(localFilePath, content);
235
+
236
+ // Recursively pull all dependencies relative to current URL
237
+ for (const relPath of relMatches) {
238
+ // Normalize extension: ensure it resolves to .d.ts on the CDN
239
+ let targetRel = relPath;
240
+ if (!targetRel.endsWith(".d.ts") && !targetRel.endsWith(".ts")) {
241
+ targetRel = `${targetRel}.d.ts`;
242
+ }
243
+
244
+ const nextUrl = new URL(targetRel, currentDtsUrl).href;
245
+ const nextLocalSubpath = path.normalize(
246
+ path.join(path.dirname(relativeSubpath), targetRel.replace(/^\.\//, ""))
247
+ );
248
+
249
+ await downloadDtsTree(nextUrl, baseDir, nextLocalSubpath, visited);
250
+ }
251
+ } catch (err) {
252
+ console.warn(` ⚠️ Failed to recursively pull: ${currentDtsUrl} -> ${err.message}`);
253
+ }
254
+ }
255
+
256
+ async function pullRemoteModuleTypes(urls) {
257
+ const typesDir = path.join(".apexkit", "types");
258
+ fs.mkdirSync(typesDir, { recursive: true });
259
+
260
+ const resolvedPaths = {};
261
+
262
+ for (const rawUrl of urls) {
263
+ try {
264
+ // Use directory container for each package to support relative child imports cleanly
265
+ const urlFolder = rawUrl.replace(/[^a-zA-Z0-9_.-]/g, "_");
266
+ const packageDir = path.join(typesDir, urlFolder);
267
+ const rootDtsFile = path.join(packageDir, "index.d.ts");
268
+
269
+ if (fs.existsSync(rootDtsFile) && fs.statSync(rootDtsFile).size > 0) {
270
+ resolvedPaths[rawUrl] = `./${rootDtsFile.replace(/\\/g, "/")}`;
271
+ continue;
272
+ }
273
+
274
+ console.log(` 🌐 [Types]: Resolving remote type tree for ${rawUrl}...`);
275
+ const dtsUrl = await resolveRemoteTypeUrl(rawUrl);
276
+
277
+ if (dtsUrl) {
278
+ fs.mkdirSync(packageDir, { recursive: true });
279
+ await downloadDtsTree(dtsUrl, packageDir, "index.d.ts");
280
+
281
+ if (fs.existsSync(rootDtsFile)) {
282
+ resolvedPaths[rawUrl] = `./${rootDtsFile.replace(/\\/g, "/")}`;
283
+ console.log(` 📦 [Types]: Successfully cached dependency tree in ${packageDir}`);
284
+ }
285
+ }
286
+ } catch (err) {
287
+ console.warn(` ⚠️ Could not pull remote types for ${rawUrl}: ${err.message}`);
288
+ }
289
+ }
290
+
291
+ return resolvedPaths;
292
+ }
293
+
294
+ // --- 5. ACCURATE WORKSPACE TYPES & CONFIG GENERATOR ---
145
295
  async function generateWorkspaceFiles() {
146
296
  console.log(" ⏳ Fetching collection schemas from DB...");
147
297
  let collectionsData = [];
@@ -332,6 +482,13 @@ export interface FileMetadata {
332
482
  visibility?: ScriptVisibility;
333
483
  }
334
484
 
485
+ export type ApexKitDb = typeof $db;
486
+ export type ApexKitHttp = typeof $http;
487
+ export type ApexKitFiles = typeof $files;
488
+ export type ApexKitFs = typeof $fs;
489
+ export type ApexKitCache = typeof $cache;
490
+ export type ApexKitEnv = typeof $env;
491
+
335
492
  export interface AuthContext {
336
493
  id: number | string;
337
494
  email: string;
@@ -369,6 +526,19 @@ export interface VoidHookEvent {
369
526
  }
370
527
 
371
528
  declare global {
529
+ namespace JSX {
530
+ interface Element extends Promise<string>, String {
531
+ [key: string]: any;
532
+ toString(): string;
533
+ }
534
+ interface IntrinsicElements {
535
+ [elemName: string]: any;
536
+ }
537
+ interface ElementChildrenAttribute {
538
+ children: {};
539
+ }
540
+ }
541
+
372
542
  const __fileMetadata__: FileMetadata;
373
543
 
374
544
  /** ApexKit Database Client */
@@ -528,10 +698,58 @@ declare global {
528
698
  base64EncodeBuffer(buffer: ArrayBuffer | Uint8Array): string;
529
699
  base64Decode(text: string): string;
530
700
  base64DecodeBuffer(text: string): ArrayBuffer;
701
+ textEncode(text: string): ArrayBuffer;
702
+ textDecode(data: ArrayBuffer | Uint8Array): string;
703
+ hexEncode(data: string | ArrayBuffer | Uint8Array): string;
704
+ hexDecode(hex: string): ArrayBuffer;
531
705
  sleep(ms: number): Promise<void>;
532
706
  randomHex(len?: number): string;
533
707
  };
534
708
 
709
+ /** Standard Web APIs */
710
+ const crypto: {
711
+ randomUUID(): string;
712
+ getRandomValues<T extends Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | null>(array: T): T;
713
+ subtle: {
714
+ digest(algorithm: string | any, data: ArrayBuffer | Uint8Array): Promise<ArrayBuffer>;
715
+ importKey(format: string, keyData: any, algo: any, extractable: boolean, usages: string[]): Promise<any>;
716
+ sign(algorithm: string | any, key: any, data: ArrayBuffer | Uint8Array): Promise<ArrayBuffer>;
717
+ verify(algorithm: string | any, key: any, signature: ArrayBuffer | Uint8Array, data: ArrayBuffer | Uint8Array): Promise<boolean>;
718
+ }
719
+ };
720
+
721
+ class Blob {
722
+ constructor(sources?: any[], options?: any);
723
+ arrayBuffer(): Promise<ArrayBuffer>;
724
+ text(): Promise<string>;
725
+ readonly size: number;
726
+ readonly type: string;
727
+ }
728
+
729
+ class ReadableStream {
730
+ constructor(underlyingSource?: any);
731
+ getReader(): any;
732
+ cancel(): Promise<void>;
733
+ readonly locked: boolean;
734
+ }
735
+
736
+ const btoa: (data: string) => string;
737
+ const atob: (data: string) => string;
738
+
739
+ class TextEncoder {
740
+ constructor(encoding?: string);
741
+ encode(input?: string): Uint8Array;
742
+ encodeInto(source: string, destination: Uint8Array): { read: number; written: number };
743
+ }
744
+
745
+ class TextDecoder {
746
+ constructor(label?: string, options?: { fatal?: boolean; ignoreBOM?: boolean });
747
+ decode(input?: ArrayBuffer | Uint8Array, options?: { stream?: boolean }): string;
748
+ }
749
+
750
+ function setTimeout(callback: Function, ms: number): string;
751
+ function clearTimeout(id: string): void;
752
+
535
753
  /** Environment & Configuration Secrets Accessor */
536
754
  const $env: {
537
755
  get(key: string): Promise<string>;
@@ -549,50 +767,122 @@ declare global {
549
767
  init?: { method?: string; headers?: any; body?: any; redirect?: "follow" | "manual" | "error" }
550
768
  ): Promise<Response>;
551
769
  }
770
+
771
+ // --- RUNTIME MODULE DEFINITIONS ---
772
+ declare module "react/jsx-runtime" {
773
+ export const jsx: any;
774
+ export const jsxs: any;
775
+ export const Fragment: any;
776
+ }
777
+
778
+ declare module "react/jsx-dev-runtime" {
779
+ export const jsxDEV: any;
780
+ export const Fragment: any;
781
+ }
782
+
783
+ declare module "hono/jsx/jsx-runtime" {
784
+ export const jsx: any;
785
+ export const jsxs: any;
786
+ export const Fragment: any;
787
+ }
788
+
789
+ declare module "hono/jsx" {
790
+ export const jsx: any;
791
+ export const jsxs: any;
792
+ export const Fragment: any;
793
+ export type FC<T = any> = (props: T) => any;
794
+ }
795
+
796
+ // --- HONO CONTEXT OVERLOADS ---
797
+ declare module "hono" {
798
+ interface Context {
799
+ html(html: string | Promise<string> | JSX.Element | any, status?: any, headers?: any): Response | Promise<Response>;
800
+ }
801
+ }
802
+
803
+ // --- REMOTE URL MODULE DECLARATIONS & FALLBACKS ---
804
+ declare module "https://*" {
805
+ const content: any;
806
+ export default content;
807
+ export * from "https://*";
808
+ }
809
+
810
+ declare module "http://*" {
811
+ const content: any;
812
+ export default content;
813
+ export * from "http://*";
814
+ }
815
+
552
816
  export {};
553
817
  `;
554
818
  fs.writeFileSync("apexkit.d.ts", types.trim());
555
- console.log(" 📄 Generated apexkit.d.ts with Accurate Scaled & Relational Typings");
819
+ console.log(" 📄 Generated apexkit.d.ts with Accurate Scaled Typings & Universal JSX");
820
+
821
+ // Dynamically scan all files and auto-pull remote module types
822
+ const remoteUrls = scanWorkspaceForRemoteUrls();
823
+ const resolvedRemoteTypes = await pullRemoteModuleTypes(remoteUrls);
824
+
825
+ const dynamicPaths = {
826
+ "@/custom/*": ["./modules/custom/*"],
827
+ "@/esm/*": ["./modules/esm/*"],
828
+ };
829
+
830
+ // Map each pulled remote URL to its local cached definition
831
+ for (const [remoteUrl, localPath] of Object.entries(resolvedRemoteTypes)) {
832
+ dynamicPaths[remoteUrl] = [localPath];
833
+ dynamicPaths[`${remoteUrl}/*`] = [`${localPath}/*`];
834
+ }
556
835
 
557
836
  const jsconfig = {
558
837
  compilerOptions: {
559
838
  target: "ES2022",
560
839
  module: "ESNext",
561
840
  ignoreDeprecations: "6.0",
562
- moduleResolution: "node",
841
+ moduleResolution: "bundler",
842
+ allowImportingTsExtensions: true,
843
+ jsx: "preserve",
563
844
  baseUrl: ".",
564
- paths: {
565
- "@/custom/*": ["./modules/custom/*"],
566
- "@/esm/*": ["./modules/esm/*"],
567
- },
845
+ paths: dynamicPaths,
568
846
  allowJs: true,
569
847
  checkJs: true,
570
848
  },
571
- include: ["**/*.js", "**/*.ts", "**/*.html", "apexkit.d.ts"],
849
+ include: [
850
+ "**/*.js",
851
+ "**/*.ts",
852
+ "**/*.jsx",
853
+ "**/*.tsx",
854
+ "**/*.html",
855
+ "apexkit.d.ts",
856
+ ".apexkit/types/**/*.d.ts",
857
+ ],
572
858
  };
573
859
  fs.writeFileSync("jsconfig.json", JSON.stringify(jsconfig, null, 2));
574
- console.log(" 📄 Generated jsconfig.json for module resolution");
860
+ console.log(" 📄 Generated jsconfig.json with Auto-Mapped Remote Types & JSX Support");
575
861
  }
576
862
 
577
863
  // --- 5. INITIAL CODE GENERATOR ---
578
864
  function getBoilerplateCode(fileType, cleanName, ext, triggerType, targetCollection) {
865
+ const metadataPath =
866
+ fileType === "template"
867
+ ? "./templates/"
868
+ : fileType.includes("module")
869
+ ? "./modules/custom/"
870
+ : "./webhooks/";
871
+
872
+ const typeImportPath = metadataPath.includes("modules/") ? "../../apexkit" : "../apexkit";
873
+
579
874
  const metadata = {
580
875
  name: cleanName,
581
876
  extension: ext,
582
877
  target_collection: targetCollection,
583
878
  type: fileType,
584
- path:
585
- fileType === "template"
586
- ? "./templates/"
587
- : fileType.includes("module")
588
- ? "./modules/custom/"
589
- : "./webhooks/",
879
+ path: metadataPath,
590
880
  trigger_type: triggerType,
591
881
  active: true,
592
882
  visibility: "private",
593
883
  };
594
884
 
595
- const header = `/** @type {import("../apexkit").FileMetadata} */\nexport const __fileMetadata__ = ${JSON.stringify(
885
+ const header = `/** @type {import("${typeImportPath}").FileMetadata} */\nexport const __fileMetadata__ = ${JSON.stringify(
596
886
  metadata,
597
887
  null,
598
888
  2
@@ -618,10 +908,11 @@ export function ${cleanName.replace(/-/g, "_")}(data = {}) {
618
908
  __fileMetadata__ = ${JSON.stringify(metadata, null, 2)}
619
909
  -->
620
910
  <script server>
621
- /// <reference path="../apexkit.d.ts" />
911
+ /** @type {import("../apexkit").ApexKitDb} */
912
+ const db = $db;
622
913
 
623
914
  export default async function (context) {
624
- const posts = await $db.records.list(\`${targetCollection || "posts"}\`, { limit: 10 }).catch(() => ({ items: [] }));
915
+ const posts = await db.records.list(\`${targetCollection || "posts"}\`, { limit: 10 }).catch(() => ({ items: [] }));
625
916
  return {
626
917
  title: \`${cleanName.replace(/-/g, " ").toUpperCase()}\`,
627
918
  items: posts.items
@@ -754,10 +1045,12 @@ async function runInitFile() {
754
1045
  }
755
1046
 
756
1047
  const cleanName = rawName.replace(/[^a-zA-Z0-9_-]/g, "");
757
- const ext =
1048
+ const allowedScriptExts = ["js", "ts", "jsx", "tsx"];
1049
+ const rawExt =
758
1050
  fileType === "template"
759
1051
  ? "html"
760
- : ((await rl.question("Extension (js/ts) [js]: ")).trim() || "js");
1052
+ : ((await rl.question("Extension (js/ts/jsx/tsx) [js]: ")).trim().toLowerCase() || "js");
1053
+ const ext = fileType === "template" ? "html" : (allowedScriptExts.includes(rawExt) ? rawExt : "js");
761
1054
 
762
1055
  let triggerType = "manual";
763
1056
  let targetCollection = null;
@@ -870,11 +1163,16 @@ async function runPull() {
870
1163
  const payload = await scriptRes.json();
871
1164
  const scripts = Array.isArray(payload) ? payload : payload.local || [];
872
1165
 
1166
+ const allowedScriptExts = ["js", "ts", "jsx", "tsx"];
1167
+
873
1168
  scripts.forEach((script) => {
1169
+ const remoteExt = script.metadata?.extension?.toLowerCase();
1170
+ const extension = allowedScriptExts.includes(remoteExt) ? remoteExt : "js";
1171
+
874
1172
  const meta = {
875
1173
  id: script.id,
876
1174
  name: script.name,
877
- extension: "js",
1175
+ extension: extension,
878
1176
  target_collection: script.target_collection || null,
879
1177
  type: script.metadata?.type || "webhook",
880
1178
  path: script.metadata?.path || "./webhooks/",
@@ -886,7 +1184,9 @@ async function runPull() {
886
1184
  const targetDir = meta.path.replace(/^\.\//, "");
887
1185
  fs.mkdirSync(targetDir, { recursive: true });
888
1186
 
889
- const formattedContent = `/** @type {import("../apexkit").FileMetadata} */\nexport const __fileMetadata__ = ${JSON.stringify(
1187
+ const typeImportPath = meta.path.includes("modules/") ? "../../apexkit" : "../apexkit";
1188
+
1189
+ const formattedContent = `/** @type {import("${typeImportPath}").FileMetadata} */\nexport const __fileMetadata__ = ${JSON.stringify(
890
1190
  meta,
891
1191
  null,
892
1192
  2
@@ -948,9 +1248,11 @@ async function runPull() {
948
1248
  console.warn(` ⚠️ AI Actions pull warning: ${e.message}`);
949
1249
  }
950
1250
 
1251
+ // Ensure .apexkit/types is ready and regenerate workspace definitions + remote types
1252
+ fs.mkdirSync(path.join(".apexkit", "types"), { recursive: true });
951
1253
  await generateWorkspaceFiles();
952
1254
 
953
- console.log(`\n✨ Pull complete! Hydrated ${pulledCount} items to local workspace.`);
1255
+ console.log(`\n✨ Pull complete! Hydrated ${pulledCount} items and resolved remote types.`);
954
1256
  process.exit(0);
955
1257
  }
956
1258
 
@@ -991,7 +1293,7 @@ function inferFileMetadata(filePath, content) {
991
1293
  return content;
992
1294
  }
993
1295
 
994
- // 3. Scripts / Webhooks / Modules -> JS Export metadata
1296
+ // 3. Scripts / Webhooks / Modules -> JS/TS/JSX/TSX Export metadata
995
1297
  let deducedType = "webhook";
996
1298
  let deducedPath = "./webhooks/";
997
1299
  let deducedTrigger = "manual";
@@ -1004,7 +1306,7 @@ function inferFileMetadata(filePath, content) {
1004
1306
  deducedPath = "./modules/esm/";
1005
1307
  }
1006
1308
 
1007
- const jsMetaRe = /(?:export\s+const\s+__fileMetadata__\s*=\s*)(\{[\s\S]*?\});?/;
1309
+ const jsMetaRe = /(?:\/\*\*[\s\S]*?\*\/\s*)?export\s+const\s+__fileMetadata__\s*=\s*(\{[\s\S]*?\});?/;
1008
1310
  const match = content.match(jsMetaRe);
1009
1311
 
1010
1312
  let metaObj = {};
@@ -1014,9 +1316,14 @@ function inferFileMetadata(filePath, content) {
1014
1316
  } catch (e) {}
1015
1317
  }
1016
1318
 
1319
+ // Prioritize real file extension if js|ts|jsx|tsx, otherwise force to js
1320
+ const allowedScriptExts = ["js", "ts", "jsx", "tsx"];
1321
+ const fileExt = ext.toLowerCase();
1322
+ const prioritizedExt = allowedScriptExts.includes(fileExt) ? fileExt : "js";
1323
+
1017
1324
  const finalMeta = {
1018
1325
  name: metaObj.name || baseName,
1019
- extension: metaObj.extension || ext || "js",
1326
+ extension: prioritizedExt,
1020
1327
  target_collection: metaObj.target_collection || null,
1021
1328
  type: metaObj.type || deducedType,
1022
1329
  path: metaObj.path || deducedPath,
@@ -1025,12 +1332,20 @@ function inferFileMetadata(filePath, content) {
1025
1332
  visibility: metaObj.visibility || "private",
1026
1333
  };
1027
1334
 
1335
+ const typeImportPath = finalMeta.path.includes("modules/") ? "../../apexkit" : "../apexkit";
1336
+ const formattedMetadata = `/** @type {import("${typeImportPath}").FileMetadata} */\nexport const __fileMetadata__ = ${JSON.stringify(
1337
+ finalMeta,
1338
+ null,
1339
+ 2
1340
+ )};`;
1341
+
1028
1342
  if (!match) {
1029
- return `/** @type {import("../apexkit").FileMetadata} */\nexport const __fileMetadata__ = ${JSON.stringify(
1030
- finalMeta,
1031
- null,
1032
- 2
1033
- )};\n\n${content}`;
1343
+ return `${formattedMetadata}\n\n${content}`;
1344
+ }
1345
+
1346
+ // If metadata extension differed or needs updating, replace with prioritized definition
1347
+ if (metaObj.extension !== prioritizedExt || content.includes('import("../apexkit")') && typeImportPath.includes("../..")) {
1348
+ return content.replace(jsMetaRe, formattedMetadata);
1034
1349
  }
1035
1350
 
1036
1351
  return content;
@@ -1345,6 +1660,8 @@ function startWatcher() {
1345
1660
  if (
1346
1661
  filename.endsWith(".js") ||
1347
1662
  filename.endsWith(".ts") ||
1663
+ filename.endsWith(".jsx") ||
1664
+ filename.endsWith(".tsx") ||
1348
1665
  filename.endsWith(".html") ||
1349
1666
  filename.endsWith(".json")
1350
1667
  ) {