@archie/devtools 0.0.48 → 0.1.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 +36 -0
- package/dist/{chunk-P5XMHBFS.mjs → chunk-THKKWDMJ.mjs} +98 -2
- package/dist/client/client.js +160 -2
- package/dist/client/client.mjs +160 -2
- package/dist/collection-binding.js +1 -0
- package/dist/collection-binding.mjs +1 -1
- package/dist/index.d.mts +92 -1
- package/dist/index.d.ts +92 -1
- package/dist/index.js +98 -2
- package/dist/index.mjs +1 -1
- package/dist/inspector.standalone.js +133 -0
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -205,6 +205,7 @@ function babelPluginDndAuto({ types: t }, opts = {}) {
|
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
// src/babel-plugin-editor-meta.ts
|
|
208
|
+
var import_editor_protocol = require("@8base-archie/editor-protocol");
|
|
208
209
|
var nodePath = __toESM(require("path"));
|
|
209
210
|
function meaningfulChildren(t, children) {
|
|
210
211
|
return children.filter((child) => {
|
|
@@ -260,7 +261,8 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
260
261
|
instrumentImported = true,
|
|
261
262
|
includeHostSourceRef = false,
|
|
262
263
|
origin = "screen",
|
|
263
|
-
templateOrigin = false
|
|
264
|
+
templateOrigin = false,
|
|
265
|
+
allowLegacyIds = true
|
|
264
266
|
} = opts;
|
|
265
267
|
function getJSXTagName(el) {
|
|
266
268
|
const { name } = el;
|
|
@@ -308,6 +310,77 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
308
310
|
function computeNodeId(file, line, col, componentName) {
|
|
309
311
|
return `${file}:${line}:${col}:${componentName}`;
|
|
310
312
|
}
|
|
313
|
+
function readVidAttr(attrs) {
|
|
314
|
+
for (const attr of attrs) {
|
|
315
|
+
if (!t.isJSXAttribute(attr)) continue;
|
|
316
|
+
if (!t.isJSXIdentifier(attr.name, { name: import_editor_protocol.VID_ATTR })) continue;
|
|
317
|
+
const { value } = attr;
|
|
318
|
+
let raw = null;
|
|
319
|
+
if (t.isStringLiteral(value)) {
|
|
320
|
+
raw = value.value;
|
|
321
|
+
} else if (t.isJSXExpressionContainer(value) && t.isStringLiteral(value.expression)) {
|
|
322
|
+
raw = value.expression.value;
|
|
323
|
+
}
|
|
324
|
+
if (raw !== null && import_editor_protocol.VID_PATTERN.test(raw)) return raw;
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
function computeDynamicType(path) {
|
|
330
|
+
let current = path.parentPath;
|
|
331
|
+
while (current) {
|
|
332
|
+
if (current.isJSXExpressionContainer()) {
|
|
333
|
+
const expr = current.node.expression;
|
|
334
|
+
if (t.isConditionalExpression(expr) || t.isLogicalExpression(expr)) {
|
|
335
|
+
return "CONDITIONAL";
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (current.isArrowFunctionExpression() || current.isFunctionExpression()) {
|
|
339
|
+
const call = current.parentPath;
|
|
340
|
+
if (call?.isCallExpression()) {
|
|
341
|
+
const callee = call.node.callee;
|
|
342
|
+
if (t.isMemberExpression(callee) && !callee.computed && t.isIdentifier(callee.property) && /^(map|flatMap|forEach)$/.test(callee.property.name)) {
|
|
343
|
+
return "ARRAY";
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
if (current.isFunctionDeclaration()) break;
|
|
349
|
+
current = current.parentPath;
|
|
350
|
+
}
|
|
351
|
+
return "STATIC";
|
|
352
|
+
}
|
|
353
|
+
const SHELL_FILE_RE = /(^|\/)shell\.jsx$/;
|
|
354
|
+
const SHELL_DIR_RE = /(^|\/)components\/shell\//;
|
|
355
|
+
const CHROME_ANCESTOR_TAGS = /* @__PURE__ */ new Set(["nav", "aside", "header"]);
|
|
356
|
+
function computeIsChrome(file, path) {
|
|
357
|
+
if (SHELL_FILE_RE.test(file) || SHELL_DIR_RE.test(file)) return true;
|
|
358
|
+
let current = path.parentPath;
|
|
359
|
+
while (current) {
|
|
360
|
+
if (current.isJSXElement()) {
|
|
361
|
+
const tag = getJSXTagName(current.node.openingElement);
|
|
362
|
+
if (CHROME_ANCESTOR_TAGS.has(tag)) return true;
|
|
363
|
+
}
|
|
364
|
+
current = current.parentPath;
|
|
365
|
+
}
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
function computeContainerKind(path) {
|
|
369
|
+
const elPath = path.parentPath;
|
|
370
|
+
if (!elPath?.isJSXElement()) return "none";
|
|
371
|
+
const children = meaningfulChildren(t, elPath.node.children);
|
|
372
|
+
if (children.length === 0) return "none";
|
|
373
|
+
const allPlain = children.every((c) => t.isJSXElement(c) || t.isJSXText(c));
|
|
374
|
+
return allPlain ? "plain" : "expression";
|
|
375
|
+
}
|
|
376
|
+
function computeLockReason(isKitOrigin, isChrome, dynamicType, containerKind) {
|
|
377
|
+
if (isKitOrigin) return "KIT_INTERNAL";
|
|
378
|
+
if (isChrome) return "CHROME_STRUCTURAL";
|
|
379
|
+
if (dynamicType === "ARRAY") return "DYNAMIC_ARRAY";
|
|
380
|
+
if (dynamicType === "CONDITIONAL") return "DYNAMIC_CONDITIONAL";
|
|
381
|
+
if (containerKind === "expression") return "EXPRESSION_CONTAINER";
|
|
382
|
+
return void 0;
|
|
383
|
+
}
|
|
311
384
|
function isMovable(path) {
|
|
312
385
|
const elPath = path.parentPath;
|
|
313
386
|
if (!elPath) return false;
|
|
@@ -325,6 +398,9 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
325
398
|
while (ancestor) {
|
|
326
399
|
if (ancestor.isJSXElement()) {
|
|
327
400
|
const opening = ancestor.node.openingElement;
|
|
401
|
+
const parentVid = readVidAttr(opening.attributes);
|
|
402
|
+
if (parentVid) return parentVid;
|
|
403
|
+
if (!allowLegacyIds) return null;
|
|
328
404
|
const loc = opening.loc?.start;
|
|
329
405
|
if (loc) {
|
|
330
406
|
const tag = getJSXTagName(opening);
|
|
@@ -951,7 +1027,9 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
951
1027
|
return;
|
|
952
1028
|
}
|
|
953
1029
|
}
|
|
954
|
-
const
|
|
1030
|
+
const vid = readVidAttr(path.node.attributes);
|
|
1031
|
+
if (!vid && !allowLegacyIds) return;
|
|
1032
|
+
const nodeId = vid ?? computeNodeId(file, line, col, componentName);
|
|
955
1033
|
const isKitOrigin = origin === "kit" || hasSlotAttr;
|
|
956
1034
|
const movable = isKitOrigin ? false : isMovable(path);
|
|
957
1035
|
const parentNodeId = getParentNodeId(path, file);
|
|
@@ -973,6 +1051,24 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
973
1051
|
parentNodeId ? t.stringLiteral(parentNodeId) : t.nullLiteral()
|
|
974
1052
|
)
|
|
975
1053
|
]);
|
|
1054
|
+
if (vid) {
|
|
1055
|
+
const dynamicType = computeDynamicType(path);
|
|
1056
|
+
const isChrome = computeIsChrome(file, path);
|
|
1057
|
+
const containerKind = computeContainerKind(path);
|
|
1058
|
+
const lockReason = computeLockReason(isKitOrigin, isChrome, dynamicType, containerKind);
|
|
1059
|
+
metaObj.properties.push(
|
|
1060
|
+
t.objectProperty(t.identifier("vid"), t.stringLiteral(vid)),
|
|
1061
|
+
t.objectProperty(t.identifier("isKitOrigin"), t.booleanLiteral(isKitOrigin)),
|
|
1062
|
+
t.objectProperty(t.identifier("dynamicType"), t.stringLiteral(dynamicType)),
|
|
1063
|
+
t.objectProperty(t.identifier("isChrome"), t.booleanLiteral(isChrome)),
|
|
1064
|
+
t.objectProperty(t.identifier("containerKind"), t.stringLiteral(containerKind))
|
|
1065
|
+
);
|
|
1066
|
+
if (lockReason) {
|
|
1067
|
+
metaObj.properties.push(
|
|
1068
|
+
t.objectProperty(t.identifier("lockReason"), t.stringLiteral(lockReason))
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
976
1072
|
if (isKitOrigin) {
|
|
977
1073
|
if (templateOrigin) {
|
|
978
1074
|
metaObj.properties.push(
|
package/dist/index.mjs
CHANGED
|
@@ -1725,10 +1725,96 @@
|
|
|
1725
1725
|
// asking blindly (and treating silence as "still unknown", never
|
|
1726
1726
|
// as "reported empty") is the correct posture.
|
|
1727
1727
|
capabilitiesQuery: true,
|
|
1728
|
+
// vid-identity migration (protocol 1.x, `@8base-archie/editor-protocol`):
|
|
1729
|
+
// this script reads `data-vid`/`meta.vid` as the node's identity
|
|
1730
|
+
// (`resolveNodeVid` below) and assembles a `NodeMeta` object for
|
|
1731
|
+
// `ELEMENT_SELECTED`, and it emits `REFUSED` instead of silently
|
|
1732
|
+
// accepting a drag/drop this package's own policy would reject.
|
|
1733
|
+
// Hosts MUST feature-detect all three: a frozen pre-migration
|
|
1734
|
+
// inspector has none of them, and its `ELEMENT_SELECTED` has no
|
|
1735
|
+
// `vid`/`nodeMeta` fields at all.
|
|
1736
|
+
vidIdentity: true,
|
|
1737
|
+
nodeMeta: true,
|
|
1738
|
+
refusals: true,
|
|
1728
1739
|
},
|
|
1729
1740
|
}
|
|
1730
1741
|
}
|
|
1731
1742
|
|
|
1743
|
+
// `@8base-archie/editor-protocol`'s `PROTOCOL_VERSION` (semver,
|
|
1744
|
+
// major-only compatibility). This script cannot `import` the shared
|
|
1745
|
+
// package (vanilla IIFE, CDN-served) — keep this literal in sync BY
|
|
1746
|
+
// HAND with that package's `src/version.ts` whenever the wire shape of
|
|
1747
|
+
// `RuntimeMessage`/`NodeMeta`/`Op` changes. Reported as a SEPARATE key
|
|
1748
|
+
// from the existing numeric `protocolVersion` above (never overwritten
|
|
1749
|
+
// — archie-app's `runtime-compatibility.ts` parses that field as a
|
|
1750
|
+
// number and compares it with strict equality; colliding the two would
|
|
1751
|
+
// silently break every existing compatibility check).
|
|
1752
|
+
var EDITOR_PROTOCOL_VERSION = "1.0.0"
|
|
1753
|
+
|
|
1754
|
+
// vid-identity migration: `/^[a-z0-9]{6,8}$/`, mirrors
|
|
1755
|
+
// `@8base-archie/editor-protocol`'s `VID_PATTERN` — kept in parity by
|
|
1756
|
+
// hand for the same reason as `EDITOR_PROTOCOL_VERSION` above.
|
|
1757
|
+
var VID_PATTERN = /^[a-z0-9]{6,8}$/
|
|
1758
|
+
|
|
1759
|
+
/**
|
|
1760
|
+
* This node's `vid` — the fiber-resolved (usage-projected) meta's
|
|
1761
|
+
* `vid` first, the DOM `data-vid` attribute next, or null. Mirrors
|
|
1762
|
+
* `node-key.ts`'s `getNodeKeyFromElement` precedence for the vid-only
|
|
1763
|
+
* portion of it (this script has no legacy-nodeId/runtime-key
|
|
1764
|
+
* fallback to offer here — callers that need a key for every element,
|
|
1765
|
+
* vid or not, keep using their own `inspectorSource` resolution).
|
|
1766
|
+
*/
|
|
1767
|
+
function resolveNodeVid(el, meta) {
|
|
1768
|
+
if (meta && typeof meta.vid === "string" && VID_PATTERN.test(meta.vid)) {
|
|
1769
|
+
return meta.vid
|
|
1770
|
+
}
|
|
1771
|
+
if (el && typeof el.getAttribute === "function") {
|
|
1772
|
+
var domVid = el.getAttribute("data-vid")
|
|
1773
|
+
if (domVid && VID_PATTERN.test(domVid)) return domVid
|
|
1774
|
+
}
|
|
1775
|
+
return null
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
/**
|
|
1779
|
+
* Assemble this node's `NodeMeta` (`@8base-archie/editor-protocol`)
|
|
1780
|
+
* from its `EditorMeta`, or null when there is no `vid` to key it by.
|
|
1781
|
+
* Mirrors `fiber-bridge.ts`'s `getNodeMeta` — kept in parity by hand,
|
|
1782
|
+
* same reason as `EDITOR_PROTOCOL_VERSION` above (this script cannot
|
|
1783
|
+
* import the TS module or run its `NodeMetaSchema.safeParse`).
|
|
1784
|
+
*/
|
|
1785
|
+
function resolveNodeMeta(el, meta) {
|
|
1786
|
+
var vid = resolveNodeVid(el, meta)
|
|
1787
|
+
if (!vid) return null
|
|
1788
|
+
var nodeMeta = {
|
|
1789
|
+
vid: vid,
|
|
1790
|
+
file: (meta && meta.file) || "",
|
|
1791
|
+
dynamicType: (meta && meta.dynamicType) || "STATIC",
|
|
1792
|
+
isKitOrigin: !!(meta && (meta.isKitOrigin || isTemplateFrame(meta))),
|
|
1793
|
+
isChrome: !!(meta && meta.isChrome),
|
|
1794
|
+
containerKind: (meta && meta.containerKind) || "none",
|
|
1795
|
+
}
|
|
1796
|
+
if (meta && meta.componentName) nodeMeta.component = meta.componentName
|
|
1797
|
+
if (meta && meta.lockReason) nodeMeta.lockReason = meta.lockReason
|
|
1798
|
+
return nodeMeta
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
/**
|
|
1802
|
+
* Emit `REFUSED` (vid-identity migration) instead of letting a
|
|
1803
|
+
* drag/drop the runtime's own policy would reject proceed silently —
|
|
1804
|
+
* the gap `docs/deploy-order.md`-adjacent decision this capability bit
|
|
1805
|
+
* documents: "today the drop is accepted and the host discards it
|
|
1806
|
+
* after the fact; that must stop."
|
|
1807
|
+
*/
|
|
1808
|
+
function refuseNode(code, cause, vid) {
|
|
1809
|
+
postMessageToParent({
|
|
1810
|
+
source: "archie-devtools",
|
|
1811
|
+
type: "REFUSED",
|
|
1812
|
+
code: code,
|
|
1813
|
+
cause: cause,
|
|
1814
|
+
vid: vid || undefined,
|
|
1815
|
+
})
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1732
1818
|
/**
|
|
1733
1819
|
* Emit the capabilities payload as `CAPABILITIES_RESULT`.
|
|
1734
1820
|
*
|
|
@@ -1745,6 +1831,7 @@
|
|
|
1745
1831
|
reason: typeof reason === "string" && reason !== "" ? reason : null,
|
|
1746
1832
|
version: handshake.version,
|
|
1747
1833
|
protocolVersion: handshake.protocolVersion,
|
|
1834
|
+
editorProtocolVersion: EDITOR_PROTOCOL_VERSION,
|
|
1748
1835
|
capabilities: handshake.capabilities,
|
|
1749
1836
|
})
|
|
1750
1837
|
}
|
|
@@ -1755,6 +1842,7 @@
|
|
|
1755
1842
|
timestamp: Date.now(),
|
|
1756
1843
|
version: initialHandshake.version,
|
|
1757
1844
|
protocolVersion: initialHandshake.protocolVersion,
|
|
1845
|
+
editorProtocolVersion: EDITOR_PROTOCOL_VERSION,
|
|
1758
1846
|
capabilities: initialHandshake.capabilities,
|
|
1759
1847
|
})
|
|
1760
1848
|
|
|
@@ -3681,6 +3769,12 @@
|
|
|
3681
3769
|
// this script's version. The slot string is opaque here; validating it
|
|
3682
3770
|
// against kit-runtime's `slot-vocabulary` is the host's job.
|
|
3683
3771
|
editorMeta: editorMeta ? editorMeta.meta : null,
|
|
3772
|
+
// vid-identity migration — `vid`/`nodeMeta` derived from the SAME
|
|
3773
|
+
// meta as `editorMeta` above (`resolveNodeVid`/`resolveNodeMeta`,
|
|
3774
|
+
// mirroring `node-key.ts`/`fiber-bridge.ts`'s `getNodeMeta`). Both
|
|
3775
|
+
// are null for a legacy node with no `data-vid`.
|
|
3776
|
+
vid: resolveNodeVid(element, editorMeta ? editorMeta.meta : null),
|
|
3777
|
+
nodeMeta: resolveNodeMeta(element, editorMeta ? editorMeta.meta : null),
|
|
3684
3778
|
// ARCH-883 F2 — the two things the host cannot derive from
|
|
3685
3779
|
// `editorMeta` alone (SDD §2.9):
|
|
3686
3780
|
//
|
|
@@ -4219,6 +4313,45 @@
|
|
|
4219
4313
|
return
|
|
4220
4314
|
}
|
|
4221
4315
|
|
|
4316
|
+
// `data-vid` identity migration — the DnD runtime's `drag-started`/
|
|
4317
|
+
// `drag-refused` events (`useDragLifecycle.ts`, `host-bridge.ts`)
|
|
4318
|
+
// otherwise die inside the iframe: nothing relayed them to the host.
|
|
4319
|
+
// Reuses `refuseNode` for `REFUSED` so the wire shape is the SAME
|
|
4320
|
+
// one produced by every other refusal path in this file (never a
|
|
4321
|
+
// second, drifting literal) and validates against
|
|
4322
|
+
// `RuntimeMessageSchema` (`@8base-archie/editor-protocol`).
|
|
4323
|
+
if (detail.type === "drag-refused") {
|
|
4324
|
+
refuseNode(detail.code, detail.cause, detail.vid)
|
|
4325
|
+
return
|
|
4326
|
+
}
|
|
4327
|
+
|
|
4328
|
+
if (detail.type === "drag-started") {
|
|
4329
|
+
// `DragStartMessageSchema.targetVid` is REQUIRED (not optional) —
|
|
4330
|
+
// unlike `REFUSED.vid`. A legacy (no `data-vid`) page's dragged
|
|
4331
|
+
// node has no vid to report, so the message cannot be made to
|
|
4332
|
+
// satisfy the schema; skip the relay rather than send a shape
|
|
4333
|
+
// that fails validation on the host. `droppable` is filtered to
|
|
4334
|
+
// well-formed vids for the same reason — the projection's own ids
|
|
4335
|
+
// can be legacy `file:line:col:componentName` strings, which the
|
|
4336
|
+
// schema's `z.array(Vid)` would reject.
|
|
4337
|
+
if (typeof detail.targetVid !== "string" || !VID_PATTERN.test(detail.targetVid)) {
|
|
4338
|
+
veTrace("runtime-event:drag-started:skipped-no-vid", {})
|
|
4339
|
+
return
|
|
4340
|
+
}
|
|
4341
|
+
var droppableVids = Array.isArray(detail.droppable)
|
|
4342
|
+
? detail.droppable.filter(function (id) {
|
|
4343
|
+
return typeof id === "string" && VID_PATTERN.test(id)
|
|
4344
|
+
})
|
|
4345
|
+
: []
|
|
4346
|
+
postMessageToParent({
|
|
4347
|
+
source: "archie-devtools",
|
|
4348
|
+
type: "DRAG_START",
|
|
4349
|
+
targetVid: detail.targetVid,
|
|
4350
|
+
droppable: droppableVids,
|
|
4351
|
+
})
|
|
4352
|
+
return
|
|
4353
|
+
}
|
|
4354
|
+
|
|
4222
4355
|
// ARCH-1367 F6 — attach the drop container's editor meta chain to a
|
|
4223
4356
|
// container descriptor ({selector, nodeId, …}). Shared by the
|
|
4224
4357
|
// `element-inserted` relay AND the `arrange-session-changed` relay:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@archie/devtools",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "DevTools for Archie generated applications - Route synchronization and editor communication",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -76,7 +76,9 @@
|
|
|
76
76
|
"react-dom": ">=18.0.0"
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
|
+
"@8base-archie/editor-protocol": "1.0.0-rc.1",
|
|
79
80
|
"@babel/core": "7.29.0",
|
|
80
|
-
"@babel/types": "7.29.0"
|
|
81
|
+
"@babel/types": "7.29.0",
|
|
82
|
+
"zod": "^4.6.5"
|
|
81
83
|
}
|
|
82
84
|
}
|