@archie/devtools 0.0.4 → 0.0.6
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 +72 -13
- package/dist/chunk-6MYORGLK.mjs +21 -0
- package/dist/{client.mjs → chunk-EQV632XF.mjs} +25 -14
- package/dist/chunk-NYVHR4QL.mjs +74 -0
- package/dist/client/client.d.mts +2 -0
- package/dist/client/client.d.ts +2 -0
- package/dist/{client.js → client/client.js} +26 -14
- package/dist/client/client.mjs +6 -0
- package/dist/client/inject-inspector/auto.d.mts +2 -0
- package/dist/client/inject-inspector/auto.d.ts +2 -0
- package/dist/client/inject-inspector/auto.js +1197 -0
- package/dist/client/inject-inspector/auto.mjs +7 -0
- package/dist/client/inject-inspector/injectInspector.d.mts +33 -0
- package/dist/client/inject-inspector/injectInspector.d.ts +33 -0
- package/dist/client/inject-inspector/injectInspector.js +1216 -0
- package/dist/client/inject-inspector/injectInspector.mjs +7 -0
- package/dist/client/route-listener/routeListener.js +90 -0
- package/dist/client/route-listener/routeListener.mjs +6 -0
- package/dist/constants/archieOrigins.d.mts +24 -0
- package/dist/constants/archieOrigins.d.ts +24 -0
- package/dist/constants/archieOrigins.js +47 -0
- package/dist/constants/archieOrigins.mjs +10 -0
- package/dist/inspector-LTHUYUGW.mjs +1094 -0
- package/package.json +21 -7
- package/dist/{client.d.mts → client/route-listener/routeListener.d.mts} +19 -19
- package/dist/{client.d.ts → client/route-listener/routeListener.d.ts} +19 -19
package/README.md
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
# @archie/devtools
|
|
2
2
|
|
|
3
|
-
DevTools for Archie generated applications.
|
|
3
|
+
DevTools for Archie generated applications. Route sync with the editor and optional element inspector script.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @archie/devtools
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @archie/devtools
|
|
9
11
|
```
|
|
10
12
|
|
|
11
13
|
## Features
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
### Vite Plugin (Optional)
|
|
18
|
-
|
|
19
|
-
Provides build-time integration for future features like component tagging and HMR overrides.
|
|
15
|
+
- **Route synchronization** – Current route is sent to the Archie editor for live preview.
|
|
16
|
+
- **Inspector script (optional)** – Injects the element inspector at runtime (no URL, bundled).
|
|
17
|
+
- **Vite plugin (optional)** – Build-time hook for future features.
|
|
20
18
|
|
|
21
19
|
## Usage
|
|
22
20
|
|
|
@@ -32,20 +30,46 @@ export default defineConfig({
|
|
|
32
30
|
});
|
|
33
31
|
```
|
|
34
32
|
|
|
35
|
-
### 2.
|
|
33
|
+
### 2. Inspector script (optional)
|
|
34
|
+
|
|
35
|
+
Injects the inspector when the client bundle runs. Safe in SSR (no-op on server). One line, no `useEffect`:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// App root, e.g. layout.tsx or main.tsx
|
|
39
|
+
import "@archie/devtools/client/inject-inspector/auto";
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**¿Afecta que la función tenga opciones?** No. El auto-import llama `injectInspector()` sin argumentos. Por defecto se usan orígenes Archie + localhost en dev y el target desde el parent (iframe). Solo si quieres cambiar algo pasas opciones:
|
|
36
43
|
|
|
37
44
|
```typescript
|
|
38
|
-
|
|
45
|
+
import { injectInspector } from "@archie/devtools/client";
|
|
46
|
+
|
|
47
|
+
// Igual que el auto: sin argumentos, valores por defecto seguros
|
|
48
|
+
injectInspector();
|
|
49
|
+
|
|
50
|
+
// Opcional: incluir localhost explícitamente, o fijar orígenes/target
|
|
51
|
+
injectInspector({ dev: true });
|
|
52
|
+
injectInspector({ id: "my-inspector" });
|
|
53
|
+
injectInspector({ allowedOrigins: ["https://app.archie.com"], targetOrigin: "https://app.archie.com" });
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Paths:
|
|
57
|
+
|
|
58
|
+
- `@archie/devtools/client` – route listener + `injectInspector`
|
|
59
|
+
- `@archie/devtools/client/inject-inspector/auto` – side-effect only (import and it runs)
|
|
60
|
+
|
|
61
|
+
### 3. Route listener (required for preview sync)
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// e.g. src/main.tsx
|
|
39
65
|
import { setupArchieRouteListener } from "@archie/devtools/client";
|
|
40
66
|
import App, { router } from "./App";
|
|
41
67
|
|
|
42
|
-
// Initialize route synchronization
|
|
43
68
|
setupArchieRouteListener(router);
|
|
44
|
-
|
|
45
69
|
createRoot(document.getElementById("root")!).render(<App />);
|
|
46
70
|
```
|
|
47
71
|
|
|
48
|
-
###
|
|
72
|
+
### 4. Export router from App
|
|
49
73
|
|
|
50
74
|
```typescript
|
|
51
75
|
// src/App.tsx
|
|
@@ -81,6 +105,41 @@ interface ArchieRouteUpdateMessage {
|
|
|
81
105
|
}
|
|
82
106
|
```
|
|
83
107
|
|
|
108
|
+
## Host (editor) integration
|
|
109
|
+
|
|
110
|
+
If your editor receives postMessage from the inspector iframe:
|
|
111
|
+
|
|
112
|
+
1. **Validate origin with an allowlist (recommended)**
|
|
113
|
+
In the **host**, allow the iframe’s origins (localhost for dev + your app URLs in production) so it works everywhere.
|
|
114
|
+
**Archie host origins:** `https://app.dev.archie-platform.com`, `https://app.staging.archie-platform.com`, `https://app.archie.com`. For local testing use `getAllowedOrigins(true)` (adds localhost). Example:
|
|
115
|
+
```js
|
|
116
|
+
import { getAllowedOrigins } from "@archie/devtools/constants";
|
|
117
|
+
const ALLOWED_ORIGINS = getAllowedOrigins(true); // true = include localhost for local dev
|
|
118
|
+
window.addEventListener("message", (e) => {
|
|
119
|
+
if (!ALLOWED_ORIGINS.includes(e.origin)) return;
|
|
120
|
+
// handle e.data
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
2. **Inspector origins (iframe):** Only configured domains are allowed; **`"*"` is never used.** If you use `injectInspector()` (recommended), it sets Archie host origins + localhost in dev by default. You can override with `allowedOrigins` and `targetOrigin` (or set `window.__ARCHIE_INSPECTOR_ALLOWED_ORIGINS__` / `__ARCHIE_INSPECTOR_TARGET_ORIGIN__` before the script runs).
|
|
124
|
+
|
|
125
|
+
4. **Globals (backward compatible)**
|
|
126
|
+
The inspector still sets `window._inspectorDebug`, `window._inspectorSelectedElement`, `window._inspectorMessageHandler`, and `window._inspectorQuerySelectorProtected`.
|
|
127
|
+
Prefer the namespace: `window.__ARCHIE_INSPECTOR__` with `debug`, `selectedElement`, `messageHandler` (same values, no DOM pollution on the namespace object).
|
|
128
|
+
|
|
129
|
+
5. **Message types** (from iframe to parent)
|
|
130
|
+
`INSPECTOR_SCRIPT_LOADED`, `ELEMENT_SELECTED`, `STOP_INSPECTION`, `INSPECTION_CANCELLED`, `ELEMENT_POSITION_UPDATE`, `STYLE_CHANGE_APPLIED` / `STYLE_CHANGE_FAILED`, `TEXT_CHANGE_APPLIED` / `TEXT_CHANGE_FAILED`, `ELEMENT_REMOVED` / `ELEMENT_REMOVAL_FAILED`.
|
|
131
|
+
Payload shapes are unchanged; only the postMessage `targetOrigin` is configurable.
|
|
132
|
+
|
|
133
|
+
To **activate the inspector from the parent** (the site that contains the iframe): you don't call `runInspector()` from the parent. The app inside the iframe already loads the inspector; from the parent send `iframe.contentWindow.postMessage({ type: "START_INSPECTION" }, iframeOrigin)` to start inspection. See [docs/HOST_INTEGRATION.md](docs/HOST_INTEGRATION.md) for full flow, local testing, and all commands.
|
|
134
|
+
|
|
135
|
+
## Linking locally
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# In the app repo
|
|
139
|
+
pnpm add file:../archie-devtools
|
|
140
|
+
# After changing the lib: run `pnpm run build` in archie-devtools
|
|
141
|
+
```
|
|
142
|
+
|
|
84
143
|
## Requirements
|
|
85
144
|
|
|
86
145
|
- React 18+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/constants/archieOrigins.ts
|
|
2
|
+
var ARCHIE_HOST_ORIGINS = [
|
|
3
|
+
"https://app.dev.archie-platform.com",
|
|
4
|
+
"https://app.staging.archie-platform.com",
|
|
5
|
+
"https://app.archie.com"
|
|
6
|
+
];
|
|
7
|
+
var LOCAL_DEV_ORIGINS = [
|
|
8
|
+
"http://localhost:3000",
|
|
9
|
+
"http://localhost:3001"
|
|
10
|
+
];
|
|
11
|
+
function getAllowedOrigins(includeLocal = false) {
|
|
12
|
+
const list = [...ARCHIE_HOST_ORIGINS];
|
|
13
|
+
if (includeLocal) list.push(...LOCAL_DEV_ORIGINS);
|
|
14
|
+
return list;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
ARCHIE_HOST_ORIGINS,
|
|
19
|
+
LOCAL_DEV_ORIGINS,
|
|
20
|
+
getAllowedOrigins
|
|
21
|
+
};
|
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
// src/client.ts
|
|
2
|
-
function setupArchieRouteListener(router) {
|
|
3
|
-
const target = window.parent !== window ? window.parent : window.opener;
|
|
4
|
-
if (!target) {
|
|
5
|
-
return () => {
|
|
6
|
-
};
|
|
7
|
-
}
|
|
8
|
-
broadcastRouteState(target, router.state, extractAllRoutes(router.routes));
|
|
9
|
-
const unsubscribe = router.subscribe((state) => {
|
|
10
|
-
const currentRoutes = extractAllRoutes(router.routes);
|
|
11
|
-
broadcastRouteState(target, state, currentRoutes);
|
|
12
|
-
});
|
|
13
|
-
return unsubscribe;
|
|
14
|
-
}
|
|
1
|
+
// src/client/route-listener/routeListener.ts
|
|
15
2
|
function extractAllRoutes(routes, parentPath = "") {
|
|
16
3
|
const result = [];
|
|
17
4
|
for (const route of routes) {
|
|
@@ -50,6 +37,30 @@ function broadcastRouteState(target, state, allRoutes) {
|
|
|
50
37
|
} catch {
|
|
51
38
|
}
|
|
52
39
|
}
|
|
40
|
+
function setupArchieRouteListener(router) {
|
|
41
|
+
const target = window.parent !== window ? window.parent : window.opener;
|
|
42
|
+
if (!target) {
|
|
43
|
+
return () => {
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
broadcastRouteState(target, router.state, extractAllRoutes(router.routes));
|
|
47
|
+
const unsubscribe = router.subscribe((state) => {
|
|
48
|
+
const currentRoutes = extractAllRoutes(router.routes);
|
|
49
|
+
broadcastRouteState(target, state, currentRoutes);
|
|
50
|
+
});
|
|
51
|
+
const handleMessage = (event) => {
|
|
52
|
+
if (event.data?.type === "ARCHIE_QUERY_ROUTES") {
|
|
53
|
+
const currentRoutes = extractAllRoutes(router.routes);
|
|
54
|
+
broadcastRouteState(target, router.state, currentRoutes);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
window.addEventListener("message", handleMessage);
|
|
58
|
+
return () => {
|
|
59
|
+
unsubscribe();
|
|
60
|
+
window.removeEventListener("message", handleMessage);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
53
64
|
export {
|
|
54
65
|
setupArchieRouteListener
|
|
55
66
|
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAllowedOrigins
|
|
3
|
+
} from "./chunk-6MYORGLK.mjs";
|
|
4
|
+
|
|
5
|
+
// src/client/inject-inspector/injectInspector.ts
|
|
6
|
+
var DEFAULT_SCRIPT_ID = "archie-inspector-script";
|
|
7
|
+
function isLocalDev(referrer) {
|
|
8
|
+
if (!referrer) return true;
|
|
9
|
+
try {
|
|
10
|
+
const u = new URL(referrer);
|
|
11
|
+
return u.hostname === "localhost" || u.hostname === "127.0.0.1";
|
|
12
|
+
} catch {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function injectInspector(opts = {}) {
|
|
17
|
+
if (typeof document === "undefined") return null;
|
|
18
|
+
const id = opts.id ?? DEFAULT_SCRIPT_ID;
|
|
19
|
+
const existing = document.getElementById(id);
|
|
20
|
+
if (existing) return Promise.resolve(existing);
|
|
21
|
+
const win = typeof window !== "undefined" ? window : null;
|
|
22
|
+
if (win) {
|
|
23
|
+
const referrer = typeof document.referrer === "string" ? document.referrer : "";
|
|
24
|
+
const dev = opts.dev ?? isLocalDev(referrer);
|
|
25
|
+
let allowed;
|
|
26
|
+
if (opts.allowedOrigins !== void 0 && opts.allowedOrigins !== "*") {
|
|
27
|
+
const v = opts.allowedOrigins;
|
|
28
|
+
allowed = typeof v === "string" ? [v] : Array.isArray(v) ? v : [];
|
|
29
|
+
} else {
|
|
30
|
+
allowed = getAllowedOrigins(dev);
|
|
31
|
+
}
|
|
32
|
+
if (allowed.length > 0) {
|
|
33
|
+
win["__ARCHIE_INSPECTOR_ALLOWED_ORIGINS__"] = allowed;
|
|
34
|
+
}
|
|
35
|
+
let target;
|
|
36
|
+
if (opts.targetOrigin !== void 0 && opts.targetOrigin !== "*") {
|
|
37
|
+
target = opts.targetOrigin || void 0;
|
|
38
|
+
} else if (referrer) {
|
|
39
|
+
try {
|
|
40
|
+
target = new URL(referrer).origin;
|
|
41
|
+
} catch {
|
|
42
|
+
target = void 0;
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
target = void 0;
|
|
46
|
+
}
|
|
47
|
+
if (target) {
|
|
48
|
+
win["__ARCHIE_INSPECTOR_TARGET_ORIGIN__"] = target;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return import("./inspector-LTHUYUGW.mjs").then((m) => {
|
|
52
|
+
try {
|
|
53
|
+
m.default();
|
|
54
|
+
} catch (err) {
|
|
55
|
+
if (typeof console !== "undefined" && console.error) {
|
|
56
|
+
console.error("[Archie DevTools] Inspector failed to run:", err);
|
|
57
|
+
}
|
|
58
|
+
throw err;
|
|
59
|
+
}
|
|
60
|
+
const script = document.createElement("script");
|
|
61
|
+
script.id = id;
|
|
62
|
+
document.head.appendChild(script);
|
|
63
|
+
return script;
|
|
64
|
+
}).catch((err) => {
|
|
65
|
+
if (typeof console !== "undefined" && console.error) {
|
|
66
|
+
console.error("[Archie DevTools] Failed to load inspector:", err);
|
|
67
|
+
}
|
|
68
|
+
throw err;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
injectInspector
|
|
74
|
+
};
|
|
@@ -17,25 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
|
|
20
|
-
// src/client.ts
|
|
20
|
+
// src/client/client.ts
|
|
21
21
|
var client_exports = {};
|
|
22
22
|
__export(client_exports, {
|
|
23
23
|
setupArchieRouteListener: () => setupArchieRouteListener
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(client_exports);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (!target) {
|
|
29
|
-
return () => {
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
broadcastRouteState(target, router.state, extractAllRoutes(router.routes));
|
|
33
|
-
const unsubscribe = router.subscribe((state) => {
|
|
34
|
-
const currentRoutes = extractAllRoutes(router.routes);
|
|
35
|
-
broadcastRouteState(target, state, currentRoutes);
|
|
36
|
-
});
|
|
37
|
-
return unsubscribe;
|
|
38
|
-
}
|
|
26
|
+
|
|
27
|
+
// src/client/route-listener/routeListener.ts
|
|
39
28
|
function extractAllRoutes(routes, parentPath = "") {
|
|
40
29
|
const result = [];
|
|
41
30
|
for (const route of routes) {
|
|
@@ -74,6 +63,29 @@ function broadcastRouteState(target, state, allRoutes) {
|
|
|
74
63
|
} catch {
|
|
75
64
|
}
|
|
76
65
|
}
|
|
66
|
+
function setupArchieRouteListener(router) {
|
|
67
|
+
const target = window.parent !== window ? window.parent : window.opener;
|
|
68
|
+
if (!target) {
|
|
69
|
+
return () => {
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
broadcastRouteState(target, router.state, extractAllRoutes(router.routes));
|
|
73
|
+
const unsubscribe = router.subscribe((state) => {
|
|
74
|
+
const currentRoutes = extractAllRoutes(router.routes);
|
|
75
|
+
broadcastRouteState(target, state, currentRoutes);
|
|
76
|
+
});
|
|
77
|
+
const handleMessage = (event) => {
|
|
78
|
+
if (event.data?.type === "ARCHIE_QUERY_ROUTES") {
|
|
79
|
+
const currentRoutes = extractAllRoutes(router.routes);
|
|
80
|
+
broadcastRouteState(target, router.state, currentRoutes);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
window.addEventListener("message", handleMessage);
|
|
84
|
+
return () => {
|
|
85
|
+
unsubscribe();
|
|
86
|
+
window.removeEventListener("message", handleMessage);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
77
89
|
// Annotate the CommonJS export names for ESM import in node:
|
|
78
90
|
0 && (module.exports = {
|
|
79
91
|
setupArchieRouteListener
|