@archie/devtools 0.0.13 → 0.0.16

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.
@@ -26,7 +26,8 @@ type InjectOptions = {
26
26
  /**
27
27
  * Where to load the inspector script from.
28
28
  * - "remote" (default): load from REMOTE_INSPECTOR_SCRIPT_URL with a dynamic hash to avoid cache.
29
- * - "local": load from the bundled module (import('./inspector.js')).
29
+ * - "local": load from `localScriptUrl` (default `/_archie/inspector.js`), served by `archieDevTools()`
30
+ * when `VITE_ARCHIE_LOCAL_INSPECTOR=true` in the host Vite app. You can also pass `localScriptUrl` directly.
30
31
  */
31
32
  scriptSource?: 'remote' | 'local';
32
33
  /**
@@ -35,6 +36,12 @@ type InjectOptions = {
35
36
  * Example: 'https://my-cdn.com/inspector.standalone.js'
36
37
  */
37
38
  scriptUrl?: string;
39
+ /**
40
+ * URL for the inspector script when `scriptSource` is `"local"`.
41
+ * Defaults to `/_archie/inspector.js` (middleware from `archieDevTools()` in dev).
42
+ * Override if you host the file elsewhere, e.g. `'http://localhost:4000/inspector.js'`.
43
+ */
44
+ localScriptUrl?: string;
38
45
  };
39
46
 
40
47
  interface ArchieRouteObjectLike {
@@ -26,7 +26,8 @@ type InjectOptions = {
26
26
  /**
27
27
  * Where to load the inspector script from.
28
28
  * - "remote" (default): load from REMOTE_INSPECTOR_SCRIPT_URL with a dynamic hash to avoid cache.
29
- * - "local": load from the bundled module (import('./inspector.js')).
29
+ * - "local": load from `localScriptUrl` (default `/_archie/inspector.js`), served by `archieDevTools()`
30
+ * when `VITE_ARCHIE_LOCAL_INSPECTOR=true` in the host Vite app. You can also pass `localScriptUrl` directly.
30
31
  */
31
32
  scriptSource?: 'remote' | 'local';
32
33
  /**
@@ -35,6 +36,12 @@ type InjectOptions = {
35
36
  * Example: 'https://my-cdn.com/inspector.standalone.js'
36
37
  */
37
38
  scriptUrl?: string;
39
+ /**
40
+ * URL for the inspector script when `scriptSource` is `"local"`.
41
+ * Defaults to `/_archie/inspector.js` (middleware from `archieDevTools()` in dev).
42
+ * Override if you host the file elsewhere, e.g. `'http://localhost:4000/inspector.js'`.
43
+ */
44
+ localScriptUrl?: string;
38
45
  };
39
46
 
40
47
  interface ArchieRouteObjectLike {
@@ -5783,7 +5783,7 @@ function applyInsertCommand(command, direction, resolveNodeElement) {
5783
5783
  var DEFAULT_LIMIT = 300;
5784
5784
  var DndCommandHistory = class {
5785
5785
  constructor(limit = DEFAULT_LIMIT) {
5786
- this.limit = limit;
5786
+ __publicField(this, "limit", limit);
5787
5787
  __publicField(this, "undoStack", []);
5788
5788
  __publicField(this, "redoStack", []);
5789
5789
  }
@@ -9114,6 +9114,16 @@ function DndProvider({ children }) {
9114
9114
  // src/client/useArchieDevToolsRuntime.ts
9115
9115
  var import_react21 = require("react");
9116
9116
 
9117
+ // src/client/archieLocalInspectorEnv.ts
9118
+ var import_meta = {};
9119
+ function readArchieLocalInspectorFlag() {
9120
+ try {
9121
+ return import_meta.env?.VITE_ARCHIE_LOCAL_INSPECTOR === "true";
9122
+ } catch {
9123
+ return false;
9124
+ }
9125
+ }
9126
+
9117
9127
  // src/client/inject-inspector/archieOrigins.ts
9118
9128
  var ARCHIE_HOST_ORIGINS = [
9119
9129
  "https://app.dev.archie-platform.com",
@@ -9169,10 +9179,10 @@ function isLocalDev(referrer) {
9169
9179
  }
9170
9180
  }
9171
9181
  function injectInspector(opts = {}) {
9172
- if (typeof document === "undefined") return null;
9182
+ if (typeof document === "undefined") return;
9173
9183
  const id = opts.id ?? DEFAULT_SCRIPT_ID;
9174
9184
  const existing = document.getElementById(id);
9175
- if (existing) return Promise.resolve(existing);
9185
+ if (existing) return;
9176
9186
  const win = typeof window !== "undefined" ? window : null;
9177
9187
  if (win) {
9178
9188
  const referrer = typeof document.referrer === "string" ? document.referrer : "";
@@ -9210,36 +9220,23 @@ function injectInspector(opts = {}) {
9210
9220
  win["__ARCHIE_INSPECTOR_TARGET_ORIGIN__"] = target;
9211
9221
  }
9212
9222
  }
9213
- const useRemote = opts.scriptSource !== "local";
9214
- if (useRemote) {
9215
- const script = document.createElement("script");
9216
- script.id = id;
9217
- script.src = getInspectorScriptUrl(opts.scriptUrl ?? REMOTE_INSPECTOR_SCRIPT_URL, true);
9218
- document.head.appendChild(script);
9219
- return null;
9220
- }
9221
- return import(
9222
- /* @vite-ignore */
9223
- "./inspector.js"
9224
- ).then((m) => {
9225
- try {
9226
- m.default();
9227
- } catch (err) {
9223
+ const useLocal = opts.scriptSource === "local";
9224
+ const scriptUrl = useLocal ? opts.localScriptUrl ?? "/_archie/inspector.js" : getInspectorScriptUrl(opts.scriptUrl ?? REMOTE_INSPECTOR_SCRIPT_URL, true);
9225
+ const script = document.createElement("script");
9226
+ script.id = id;
9227
+ script.src = scriptUrl;
9228
+ if (useLocal) {
9229
+ script.onerror = () => {
9228
9230
  if (typeof console !== "undefined" && console.error) {
9229
- console.error("[Archie DevTools] Inspector failed to run:", err);
9231
+ console.error(
9232
+ "[Archie DevTools] Failed to load local inspector from",
9233
+ scriptUrl,
9234
+ "\u2014 is archieDevTools() registered in your vite.config?"
9235
+ );
9230
9236
  }
9231
- throw err;
9232
- }
9233
- const script = document.createElement("script");
9234
- script.id = id;
9235
- document.head.appendChild(script);
9236
- return script;
9237
- }).catch((err) => {
9238
- if (typeof console !== "undefined" && console.error) {
9239
- console.error("[Archie DevTools] Failed to load inspector:", err);
9240
- }
9241
- throw err;
9242
- });
9237
+ };
9238
+ }
9239
+ document.head.appendChild(script);
9243
9240
  }
9244
9241
 
9245
9242
  // src/client/route-listener/routeListener.ts
@@ -9348,9 +9345,9 @@ function useArchieDevToolsRuntime({
9348
9345
  }
9349
9346
  const unsubscribe = setupArchieRouteListener(router);
9350
9347
  if (inspector !== false) {
9351
- const isLocalHost = typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1");
9348
+ const useLocalInspector = readArchieLocalInspectorFlag();
9352
9349
  injectInspector({
9353
- scriptSource: isLocalHost ? "local" : "remote",
9350
+ ...useLocalInspector ? { scriptSource: "local" } : { scriptSource: "remote" },
9354
9351
  ...inspectorOptionsRef.current
9355
9352
  });
9356
9353
  }
@@ -1,6 +1,6 @@
1
- import {
2
- __publicField
3
- } from "../chunk-QZ7TP4HQ.mjs";
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key2, value) => key2 in obj ? __defProp(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value;
3
+ var __publicField = (obj, key2, value) => __defNormalProp(obj, typeof key2 !== "symbol" ? key2 + "" : key2, value);
4
4
 
5
5
  // src/client/dnd/DndProvider.tsx
6
6
  import { useCallback as useCallback9, useEffect as useEffect13 } from "react";
@@ -5749,7 +5749,7 @@ function applyInsertCommand(command, direction, resolveNodeElement) {
5749
5749
  var DEFAULT_LIMIT = 300;
5750
5750
  var DndCommandHistory = class {
5751
5751
  constructor(limit = DEFAULT_LIMIT) {
5752
- this.limit = limit;
5752
+ __publicField(this, "limit", limit);
5753
5753
  __publicField(this, "undoStack", []);
5754
5754
  __publicField(this, "redoStack", []);
5755
5755
  }
@@ -9080,6 +9080,15 @@ function DndProvider({ children }) {
9080
9080
  // src/client/useArchieDevToolsRuntime.ts
9081
9081
  import { useEffect as useEffect14, useRef as useRef11 } from "react";
9082
9082
 
9083
+ // src/client/archieLocalInspectorEnv.ts
9084
+ function readArchieLocalInspectorFlag() {
9085
+ try {
9086
+ return import.meta.env?.VITE_ARCHIE_LOCAL_INSPECTOR === "true";
9087
+ } catch {
9088
+ return false;
9089
+ }
9090
+ }
9091
+
9083
9092
  // src/client/inject-inspector/archieOrigins.ts
9084
9093
  var ARCHIE_HOST_ORIGINS = [
9085
9094
  "https://app.dev.archie-platform.com",
@@ -9135,10 +9144,10 @@ function isLocalDev(referrer) {
9135
9144
  }
9136
9145
  }
9137
9146
  function injectInspector(opts = {}) {
9138
- if (typeof document === "undefined") return null;
9147
+ if (typeof document === "undefined") return;
9139
9148
  const id = opts.id ?? DEFAULT_SCRIPT_ID;
9140
9149
  const existing = document.getElementById(id);
9141
- if (existing) return Promise.resolve(existing);
9150
+ if (existing) return;
9142
9151
  const win = typeof window !== "undefined" ? window : null;
9143
9152
  if (win) {
9144
9153
  const referrer = typeof document.referrer === "string" ? document.referrer : "";
@@ -9176,36 +9185,23 @@ function injectInspector(opts = {}) {
9176
9185
  win["__ARCHIE_INSPECTOR_TARGET_ORIGIN__"] = target;
9177
9186
  }
9178
9187
  }
9179
- const useRemote = opts.scriptSource !== "local";
9180
- if (useRemote) {
9181
- const script = document.createElement("script");
9182
- script.id = id;
9183
- script.src = getInspectorScriptUrl(opts.scriptUrl ?? REMOTE_INSPECTOR_SCRIPT_URL, true);
9184
- document.head.appendChild(script);
9185
- return null;
9186
- }
9187
- return import(
9188
- /* @vite-ignore */
9189
- "./inspector.js"
9190
- ).then((m) => {
9191
- try {
9192
- m.default();
9193
- } catch (err) {
9188
+ const useLocal = opts.scriptSource === "local";
9189
+ const scriptUrl = useLocal ? opts.localScriptUrl ?? "/_archie/inspector.js" : getInspectorScriptUrl(opts.scriptUrl ?? REMOTE_INSPECTOR_SCRIPT_URL, true);
9190
+ const script = document.createElement("script");
9191
+ script.id = id;
9192
+ script.src = scriptUrl;
9193
+ if (useLocal) {
9194
+ script.onerror = () => {
9194
9195
  if (typeof console !== "undefined" && console.error) {
9195
- console.error("[Archie DevTools] Inspector failed to run:", err);
9196
+ console.error(
9197
+ "[Archie DevTools] Failed to load local inspector from",
9198
+ scriptUrl,
9199
+ "\u2014 is archieDevTools() registered in your vite.config?"
9200
+ );
9196
9201
  }
9197
- throw err;
9198
- }
9199
- const script = document.createElement("script");
9200
- script.id = id;
9201
- document.head.appendChild(script);
9202
- return script;
9203
- }).catch((err) => {
9204
- if (typeof console !== "undefined" && console.error) {
9205
- console.error("[Archie DevTools] Failed to load inspector:", err);
9206
- }
9207
- throw err;
9208
- });
9202
+ };
9203
+ }
9204
+ document.head.appendChild(script);
9209
9205
  }
9210
9206
 
9211
9207
  // src/client/route-listener/routeListener.ts
@@ -9314,9 +9310,9 @@ function useArchieDevToolsRuntime({
9314
9310
  }
9315
9311
  const unsubscribe = setupArchieRouteListener(router);
9316
9312
  if (inspector !== false) {
9317
- const isLocalHost = typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1");
9313
+ const useLocalInspector = readArchieLocalInspectorFlag();
9318
9314
  injectInspector({
9319
- scriptSource: isLocalHost ? "local" : "remote",
9315
+ ...useLocalInspector ? { scriptSource: "local" } : { scriptSource: "remote" },
9320
9316
  ...inspectorOptionsRef.current
9321
9317
  });
9322
9318
  }
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { ResolvedConfig } from 'vite';
1
+ import { ResolvedConfig, ViteDevServer } from 'vite';
2
2
 
3
3
  interface ArchieDevToolsOptions {
4
4
  /**
@@ -15,12 +15,13 @@ interface ArchieDevToolsOptions {
15
15
  interface ArchieDevToolsPlugin {
16
16
  name: string;
17
17
  enforce?: 'pre' | 'post';
18
- config?: () => {
19
- resolve: {
20
- dedupe: string[];
21
- };
22
- };
18
+ config?: () => object;
23
19
  configResolved?: (config: ResolvedConfig) => void;
20
+ configureServer?: (server: ViteDevServer) => void;
21
+ transform?: (code: string, id: string) => Promise<{
22
+ code: string;
23
+ map?: object | null;
24
+ } | null | undefined>;
24
25
  resolveId?: (id: string) => string | null;
25
26
  load?: (id: string) => string | null;
26
27
  api?: {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ResolvedConfig } from 'vite';
1
+ import { ResolvedConfig, ViteDevServer } from 'vite';
2
2
 
3
3
  interface ArchieDevToolsOptions {
4
4
  /**
@@ -15,12 +15,13 @@ interface ArchieDevToolsOptions {
15
15
  interface ArchieDevToolsPlugin {
16
16
  name: string;
17
17
  enforce?: 'pre' | 'post';
18
- config?: () => {
19
- resolve: {
20
- dedupe: string[];
21
- };
22
- };
18
+ config?: () => object;
23
19
  configResolved?: (config: ResolvedConfig) => void;
20
+ configureServer?: (server: ViteDevServer) => void;
21
+ transform?: (code: string, id: string) => Promise<{
22
+ code: string;
23
+ map?: object | null;
24
+ } | null | undefined>;
24
25
  resolveId?: (id: string) => string | null;
25
26
  load?: (id: string) => string | null;
26
27
  api?: {
package/dist/index.js CHANGED
@@ -28,11 +28,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
30
  // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
33
  archieDevTools: () => archieDevTools
34
34
  });
35
- module.exports = __toCommonJS(index_exports);
35
+ module.exports = __toCommonJS(src_exports);
36
+ var import_node_fs = require("fs");
37
+ var import_node_path = require("path");
36
38
 
37
39
  // src/client/dnd/virtual/dndScopeVirtualModule.ts
38
40
  var INTERNAL_DND_SCOPE_IMPORT_SOURCE = "virtual:archie-devtools/dnd-scope";
@@ -483,6 +485,7 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
483
485
  }
484
486
 
485
487
  // src/index.ts
488
+ var LOCAL_INSPECTOR_SERVE_PATH = "/_archie/inspector.js";
486
489
  function archieDevTools(options = {}) {
487
490
  const {
488
491
  debug = false,
@@ -491,7 +494,9 @@ function archieDevTools(options = {}) {
491
494
  const log = (...args) => {
492
495
  if (debug) console.log("[Archie DevTools]", ...args);
493
496
  };
497
+ let babelCore = null;
494
498
  let includeHostSourceRef = false;
499
+ const transformedByHook = /* @__PURE__ */ new Set();
495
500
  const plugin = {
496
501
  name: "vite-plugin-archie-devtools",
497
502
  enforce: "pre",
@@ -499,12 +504,56 @@ function archieDevTools(options = {}) {
499
504
  return {
500
505
  resolve: {
501
506
  dedupe: ["react", "react-dom"]
507
+ },
508
+ optimizeDeps: {
509
+ exclude: ["@archie/devtools/client"]
502
510
  }
503
511
  };
504
512
  },
505
513
  configResolved(config) {
506
514
  includeHostSourceRef = !config.isProduction;
507
515
  },
516
+ configureServer(server) {
517
+ server.middlewares.use(LOCAL_INSPECTOR_SERVE_PATH, (_req, res) => {
518
+ const standaloneFile = (0, import_node_path.join)(__dirname, "../src/client/inject-inspector/inspector.standalone.js");
519
+ try {
520
+ const content = (0, import_node_fs.readFileSync)(standaloneFile, "utf-8");
521
+ res.setHeader("Content-Type", "application/javascript; charset=utf-8");
522
+ res.setHeader("Cache-Control", "no-store");
523
+ res.end(content);
524
+ } catch {
525
+ res.statusCode = 404;
526
+ res.end("Not found");
527
+ }
528
+ });
529
+ },
530
+ async transform(code, id) {
531
+ if (!/\.[jt]sx$/.test(id) || /node_modules/.test(id)) return null;
532
+ try {
533
+ const babel = babelCore ?? (babelCore = await import("@babel/core"));
534
+ const isTS = /\.tsx$/.test(id);
535
+ const result = await babel.transformAsync(code, {
536
+ filename: id,
537
+ plugins: [
538
+ (b) => babelPluginEditorMeta(b, { includeHostSourceRef }),
539
+ ...dndPages.test(id) ? [(b) => babelPluginDndAuto(b, { importSource: INTERNAL_DND_SCOPE_IMPORT_SOURCE })] : []
540
+ ],
541
+ parserOpts: {
542
+ plugins: isTS ? ["jsx", "typescript"] : ["jsx"],
543
+ sourceType: "module"
544
+ },
545
+ sourceMaps: true,
546
+ configFile: false,
547
+ babelrc: false
548
+ });
549
+ if (!result?.code) return null;
550
+ transformedByHook.add(id);
551
+ return { code: result.code, map: result.map };
552
+ } catch (err) {
553
+ log("Babel transform failed for:", id, err);
554
+ return null;
555
+ }
556
+ },
508
557
  resolveId(id) {
509
558
  if (id === INTERNAL_DND_SCOPE_IMPORT_SOURCE) {
510
559
  return RESOLVED_DND_SCOPE_MODULE_ID;
@@ -519,14 +568,14 @@ function archieDevTools(options = {}) {
519
568
  },
520
569
  api: {
521
570
  reactBabel(babelOptions, context) {
522
- if (!/node_modules/.test(context.id)) {
571
+ if (!/node_modules/.test(context.id) && !transformedByHook.has(context.id)) {
523
572
  babelOptions.plugins.push(
524
573
  (babel) => babelPluginEditorMeta(babel, {
525
574
  includeHostSourceRef
526
575
  })
527
576
  );
528
577
  }
529
- if (dndPages.test(context.id)) {
578
+ if (dndPages.test(context.id) && !transformedByHook.has(context.id)) {
530
579
  log("Applying DnD transform to:", context.id);
531
580
  babelOptions.plugins.push(
532
581
  (babel) => babelPluginDndAuto(babel, {
package/dist/index.mjs CHANGED
@@ -1,4 +1,13 @@
1
- import "./chunk-QZ7TP4HQ.mjs";
1
+ // node_modules/tsup/assets/esm_shims.js
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ var getFilename = () => fileURLToPath(import.meta.url);
5
+ var getDirname = () => path.dirname(getFilename());
6
+ var __dirname = /* @__PURE__ */ getDirname();
7
+
8
+ // src/index.ts
9
+ import { readFileSync } from "fs";
10
+ import { join } from "path";
2
11
 
3
12
  // src/client/dnd/virtual/dndScopeVirtualModule.ts
4
13
  var INTERNAL_DND_SCOPE_IMPORT_SOURCE = "virtual:archie-devtools/dnd-scope";
@@ -129,16 +138,16 @@ function babelPluginDndAuto({ types: t }, opts = {}) {
129
138
  return {
130
139
  name: "babel-plugin-dnd-auto",
131
140
  visitor: {
132
- ExportDefaultDeclaration(path, state) {
141
+ ExportDefaultDeclaration(path2, state) {
133
142
  const filename = state.filename ?? "";
134
143
  if (fileExclude.test(filename)) return;
135
144
  if (fileMatch && !fileMatch.test(filename)) return;
136
- const { declaration } = path.node;
145
+ const { declaration } = path2.node;
137
146
  if (!t.isFunctionDeclaration(declaration)) return;
138
147
  const componentName = declaration.id?.name ?? "Component";
139
148
  const scopeCounter = { n: 0 };
140
149
  let didTransform = false;
141
- path.traverse({
150
+ path2.traverse({
142
151
  ReturnStatement(retPath) {
143
152
  const fnParent = retPath.getFunctionParent();
144
153
  if (fnParent?.node !== declaration) return;
@@ -208,8 +217,8 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
208
217
  function computeNodeId(file, line, col, componentName) {
209
218
  return `${file}:${line}:${col}:${componentName}`;
210
219
  }
211
- function isMovable(path) {
212
- const elPath = path.parentPath;
220
+ function isMovable(path2) {
221
+ const elPath = path2.parentPath;
213
222
  if (!elPath) return false;
214
223
  const parentEl = elPath.parentPath;
215
224
  if (!parentEl || !parentEl.isJSXElement()) return false;
@@ -218,8 +227,8 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
218
227
  );
219
228
  return siblings.length >= 2;
220
229
  }
221
- function getParentNodeId(path, file) {
222
- const elPath = path.parentPath;
230
+ function getParentNodeId(path2, file) {
231
+ const elPath = path2.parentPath;
223
232
  if (!elPath) return null;
224
233
  let ancestor = elPath.parentPath;
225
234
  while (ancestor) {
@@ -323,10 +332,10 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
323
332
  return {
324
333
  name: "babel-plugin-editor-meta",
325
334
  visitor: {
326
- CallExpression(path, state) {
335
+ CallExpression(path2, state) {
327
336
  const filename = state.filename ?? "";
328
337
  if (fileExclude.test(filename)) return;
329
- const callee = path.node.callee;
338
+ const callee = path2.node.callee;
330
339
  let isCreateElement = false;
331
340
  let isCloneElement = false;
332
341
  if (t.isIdentifier(callee, { name: "createElement" })) {
@@ -339,7 +348,7 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
339
348
  isCloneElement = true;
340
349
  }
341
350
  if (!isCreateElement && !isCloneElement) return;
342
- const args = path.node.arguments;
351
+ const args = path2.node.arguments;
343
352
  if (args.length < 2) return;
344
353
  if (isCreateElement && !t.isStringLiteral(args[0])) return;
345
354
  const propsArg = args[1];
@@ -364,37 +373,37 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
364
373
  [t.objectExpression([t.spreadElement(propsArg)])]
365
374
  );
366
375
  },
367
- JSXOpeningElement(path, state) {
376
+ JSXOpeningElement(path2, state) {
368
377
  const filename = state.filename ?? "";
369
378
  if (fileExclude.test(filename)) return;
370
- const existing = path.node.attributes.find(
379
+ const existing = path2.node.attributes.find(
371
380
  (a) => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name, { name: "__editorMeta" })
372
381
  );
373
382
  if (existing) return;
374
- const loc = path.node.loc?.start;
383
+ const loc = path2.node.loc?.start;
375
384
  if (!loc) return;
376
385
  const root = state.file.opts.root ?? "";
377
386
  const file = root ? nodePath.relative(root, filename) : filename;
378
387
  const line = loc.line;
379
388
  const col = loc.column + 1;
380
- const componentName = getJSXTagName(path.node);
389
+ const componentName = getJSXTagName(path2.node);
381
390
  if (!componentName) return;
382
- const isHostLikeMemberExpression = isHostLikeMemberExpressionName(path.node.name);
391
+ const isHostLikeMemberExpression = isHostLikeMemberExpressionName(path2.node.name);
383
392
  const isHostElement = componentName[0] === componentName[0].toLowerCase();
384
- sanitizeSpreadAttributes(path.node.attributes);
385
- if (hasTruthyAsChildProp(path.node.attributes)) {
393
+ sanitizeSpreadAttributes(path2.node.attributes);
394
+ if (hasTruthyAsChildProp(path2.node.attributes)) {
386
395
  return;
387
396
  }
388
397
  let rootName = null;
389
- if (t.isJSXIdentifier(path.node.name)) {
390
- rootName = path.node.name.name;
391
- } else if (t.isJSXMemberExpression(path.node.name)) {
392
- let cur = path.node.name;
398
+ if (t.isJSXIdentifier(path2.node.name)) {
399
+ rootName = path2.node.name.name;
400
+ } else if (t.isJSXMemberExpression(path2.node.name)) {
401
+ let cur = path2.node.name;
393
402
  while (t.isJSXMemberExpression(cur)) cur = cur.object;
394
403
  if (t.isJSXIdentifier(cur)) rootName = cur.name;
395
404
  }
396
405
  if (rootName) {
397
- const binding = path.scope.getBinding(rootName);
406
+ const binding = path2.scope.getBinding(rootName);
398
407
  if (binding) {
399
408
  const bp = binding.path;
400
409
  if (bp.isImportSpecifier() || bp.isImportDefaultSpecifier() || bp.isImportNamespaceSpecifier()) {
@@ -405,14 +414,14 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
405
414
  if (isPackageImport(src) && !isHostLikeMemberExpression) return;
406
415
  }
407
416
  }
408
- const programScope = path.scope.getProgramParent();
417
+ const programScope = path2.scope.getProgramParent();
409
418
  if (binding.scope !== programScope) return;
410
419
  }
411
420
  }
412
421
  const nodeId = computeNodeId(file, line, col, componentName);
413
- const movable = isMovable(path);
414
- const parentNodeId = getParentNodeId(path, file);
415
- const staticPropsObj = extractStaticProps(path.node.attributes);
422
+ const movable = isMovable(path2);
423
+ const parentNodeId = getParentNodeId(path2, file);
424
+ const staticPropsObj = extractStaticProps(path2.node.attributes);
416
425
  const metaObj = t.objectExpression([
417
426
  t.objectProperty(t.identifier("nodeId"), t.stringLiteral(nodeId)),
418
427
  t.objectProperty(t.identifier("file"), t.stringLiteral(file)),
@@ -430,14 +439,14 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
430
439
  )
431
440
  ]);
432
441
  if (isHostElement && includeHostSourceRef) {
433
- path.node.attributes.push(
442
+ path2.node.attributes.push(
434
443
  t.jsxAttribute(
435
444
  t.jsxIdentifier("data-archie-source-ref"),
436
445
  t.stringLiteral(`${file}::${line}::${col}`)
437
446
  )
438
447
  );
439
448
  }
440
- path.node.attributes.push(
449
+ path2.node.attributes.push(
441
450
  t.jsxAttribute(
442
451
  t.jsxIdentifier("__editorMeta"),
443
452
  t.jsxExpressionContainer(metaObj)
@@ -449,6 +458,7 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
449
458
  }
450
459
 
451
460
  // src/index.ts
461
+ var LOCAL_INSPECTOR_SERVE_PATH = "/_archie/inspector.js";
452
462
  function archieDevTools(options = {}) {
453
463
  const {
454
464
  debug = false,
@@ -457,7 +467,9 @@ function archieDevTools(options = {}) {
457
467
  const log = (...args) => {
458
468
  if (debug) console.log("[Archie DevTools]", ...args);
459
469
  };
470
+ let babelCore = null;
460
471
  let includeHostSourceRef = false;
472
+ const transformedByHook = /* @__PURE__ */ new Set();
461
473
  const plugin = {
462
474
  name: "vite-plugin-archie-devtools",
463
475
  enforce: "pre",
@@ -465,12 +477,56 @@ function archieDevTools(options = {}) {
465
477
  return {
466
478
  resolve: {
467
479
  dedupe: ["react", "react-dom"]
480
+ },
481
+ optimizeDeps: {
482
+ exclude: ["@archie/devtools/client"]
468
483
  }
469
484
  };
470
485
  },
471
486
  configResolved(config) {
472
487
  includeHostSourceRef = !config.isProduction;
473
488
  },
489
+ configureServer(server) {
490
+ server.middlewares.use(LOCAL_INSPECTOR_SERVE_PATH, (_req, res) => {
491
+ const standaloneFile = join(__dirname, "../src/client/inject-inspector/inspector.standalone.js");
492
+ try {
493
+ const content = readFileSync(standaloneFile, "utf-8");
494
+ res.setHeader("Content-Type", "application/javascript; charset=utf-8");
495
+ res.setHeader("Cache-Control", "no-store");
496
+ res.end(content);
497
+ } catch {
498
+ res.statusCode = 404;
499
+ res.end("Not found");
500
+ }
501
+ });
502
+ },
503
+ async transform(code, id) {
504
+ if (!/\.[jt]sx$/.test(id) || /node_modules/.test(id)) return null;
505
+ try {
506
+ const babel = babelCore ?? (babelCore = await import("@babel/core"));
507
+ const isTS = /\.tsx$/.test(id);
508
+ const result = await babel.transformAsync(code, {
509
+ filename: id,
510
+ plugins: [
511
+ (b) => babelPluginEditorMeta(b, { includeHostSourceRef }),
512
+ ...dndPages.test(id) ? [(b) => babelPluginDndAuto(b, { importSource: INTERNAL_DND_SCOPE_IMPORT_SOURCE })] : []
513
+ ],
514
+ parserOpts: {
515
+ plugins: isTS ? ["jsx", "typescript"] : ["jsx"],
516
+ sourceType: "module"
517
+ },
518
+ sourceMaps: true,
519
+ configFile: false,
520
+ babelrc: false
521
+ });
522
+ if (!result?.code) return null;
523
+ transformedByHook.add(id);
524
+ return { code: result.code, map: result.map };
525
+ } catch (err) {
526
+ log("Babel transform failed for:", id, err);
527
+ return null;
528
+ }
529
+ },
474
530
  resolveId(id) {
475
531
  if (id === INTERNAL_DND_SCOPE_IMPORT_SOURCE) {
476
532
  return RESOLVED_DND_SCOPE_MODULE_ID;
@@ -485,14 +541,14 @@ function archieDevTools(options = {}) {
485
541
  },
486
542
  api: {
487
543
  reactBabel(babelOptions, context) {
488
- if (!/node_modules/.test(context.id)) {
544
+ if (!/node_modules/.test(context.id) && !transformedByHook.has(context.id)) {
489
545
  babelOptions.plugins.push(
490
546
  (babel) => babelPluginEditorMeta(babel, {
491
547
  includeHostSourceRef
492
548
  })
493
549
  );
494
550
  }
495
- if (dndPages.test(context.id)) {
551
+ if (dndPages.test(context.id) && !transformedByHook.has(context.id)) {
496
552
  log("Applying DnD transform to:", context.id);
497
553
  babelOptions.plugins.push(
498
554
  (babel) => babelPluginDndAuto(babel, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archie/devtools",
3
- "version": "0.0.13",
3
+ "version": "0.0.16",
4
4
  "description": "DevTools for Archie generated applications - Route synchronization and editor communication",
5
5
  "repository": {
6
6
  "type": "git",
@@ -47,25 +47,25 @@
47
47
  "author": "8base",
48
48
  "license": "UNLICENSED",
49
49
  "devDependencies": {
50
- "@babel/core": "^7.29.0",
51
- "@babel/types": "^7.29.0",
52
- "@dnd-kit/core": "^6.3.1",
53
- "@dnd-kit/sortable": "^10.0.0",
54
- "@dnd-kit/utilities": "^3.2.2",
55
- "@remix-run/router": "^1.0.0",
56
- "@types/babel__core": "^7.20.5",
57
- "@types/react": "^19.0.0",
58
- "@types/react-dom": "^19.0.0",
59
- "happy-dom": "^20.5.0",
60
- "lucide-react": "^0.577.0",
61
- "react": "^19.0.0",
62
- "react-dom": "^19.0.0",
63
- "react-router-dom": "^7.0.0",
64
- "tsup": "^8.0.0",
65
- "typescript": "^5.0.0",
66
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
67
- "vitest": "^2.1.9",
68
- "zustand": "^5.0.11"
50
+ "@babel/core": "7.29.0",
51
+ "@babel/types": "7.29.0",
52
+ "@dnd-kit/core": "6.3.1",
53
+ "@dnd-kit/sortable": "10.0.0",
54
+ "@dnd-kit/utilities": "3.2.2",
55
+ "@remix-run/router": "1.23.2",
56
+ "@types/babel__core": "7.20.5",
57
+ "@types/react": "19.2.14",
58
+ "@types/react-dom": "19.2.3",
59
+ "happy-dom": "20.8.9",
60
+ "lucide-react": "0.577.0",
61
+ "react": "19.2.4",
62
+ "react-dom": "19.2.4",
63
+ "react-router-dom": "7.14.0",
64
+ "tsup": "8.5.1",
65
+ "typescript": "5.9.3",
66
+ "vite": "7.3.2",
67
+ "vitest": "4.1.3",
68
+ "zustand": "5.0.12"
69
69
  },
70
70
  "peerDependencies": {
71
71
  "react": ">=18.0.0",
@@ -1,7 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
-
5
- export {
6
- __publicField
7
- };