@archie/devtools 0.1.1 → 0.1.3

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
@@ -89,6 +89,11 @@ opción `allowLegacyIds` es `true` (default en esta versión — transicional,
89
89
  se eliminará más adelante); con `allowLegacyIds: false` el elemento no se
90
90
  instrumenta.
91
91
 
92
+ El plugin nunca estampa `data-vid` en runtime (eso lo hace el stamper de
93
+ Genesis). El plugin Vite (`archieDevTools()`) solo VALIDA: en dev, un
94
+ `JSXOpeningElement` sin `data-vid` dispara un warning una vez por archivo
95
+ (`onMissingVid` en `babel-plugin-editor-meta.ts`).
96
+
92
97
  En runtime, `node-key.ts` resuelve la identidad con la prioridad
93
98
  `meta.vid` → `data-vid` del DOM → (legado) `meta.nodeId` → `runtime:N`, y
94
99
  `fiber-bridge.ts` expone `getNodeMeta(el)`, que valida el `NodeMeta`
@@ -63,8 +63,10 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
63
63
  includeHostSourceRef = false,
64
64
  origin = "screen",
65
65
  templateOrigin = false,
66
- allowLegacyIds = true
66
+ allowLegacyIds = true,
67
+ onMissingVid
67
68
  } = opts;
69
+ let missingVidWarned = false;
68
70
  function getJSXTagName(el) {
69
71
  const { name } = el;
70
72
  if (t.isJSXIdentifier(name)) return name.name;
@@ -151,11 +153,17 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
151
153
  }
152
154
  return "STATIC";
153
155
  }
154
- const SHELL_FILE_RE = /(^|\/)shell\.jsx$/;
156
+ const SHELL_FILE_RE = /(^|\/)shell\.(jsx|tsx)$/;
155
157
  const SHELL_DIR_RE = /(^|\/)components\/shell\//;
158
+ const SHELL_BASENAME_RE = /shell/i;
156
159
  const CHROME_ANCESTOR_TAGS = /* @__PURE__ */ new Set(["nav", "aside", "header"]);
157
- function computeIsChrome(file, path2) {
160
+ function isChromeFilePath(file) {
158
161
  if (SHELL_FILE_RE.test(file) || SHELL_DIR_RE.test(file)) return true;
162
+ const base = file.split("/").pop() ?? file;
163
+ return SHELL_BASENAME_RE.test(base);
164
+ }
165
+ function computeIsChrome(file, path2) {
166
+ if (isChromeFilePath(file)) return true;
159
167
  let current = path2.parentPath;
160
168
  while (current) {
161
169
  if (current.isJSXElement()) {
@@ -169,17 +177,65 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
169
177
  function computeContainerKind(path2) {
170
178
  const elPath = path2.parentPath;
171
179
  if (!elPath?.isJSXElement()) return "none";
172
- const children = meaningfulChildren(t, elPath.node.children);
173
- if (children.length === 0) return "none";
174
- const allPlain = children.every((c) => t.isJSXElement(c) || t.isJSXText(c));
180
+ if (!elPath.node.closingElement) return "none";
181
+ const children = elPath.node.children;
182
+ const allPlain = children.every((c) => {
183
+ if (t.isJSXElement(c)) return true;
184
+ if (t.isJSXText(c)) return c.value.trim() === "";
185
+ return false;
186
+ });
175
187
  return allPlain ? "plain" : "expression";
176
188
  }
177
- function computeLockReason(isKitOrigin, isChrome, dynamicType, containerKind) {
189
+ const kitBoundNamesCache = /* @__PURE__ */ new WeakMap();
190
+ function computeKitBoundNames(programPath) {
191
+ const cached = kitBoundNamesCache.get(programPath.node);
192
+ if (cached) return cached;
193
+ const names = /* @__PURE__ */ new Set();
194
+ for (const stmt of programPath.node.body) {
195
+ if (!t.isVariableDeclaration(stmt)) continue;
196
+ for (const decl of stmt.declarations) {
197
+ if (!t.isObjectPattern(decl.id)) continue;
198
+ if (!decl.init || !t.isIdentifier(decl.init) || decl.init.name !== "Kit") continue;
199
+ for (const prop of decl.id.properties) {
200
+ if (!t.isObjectProperty(prop)) continue;
201
+ const value = t.isIdentifier(prop.value) ? prop.value : t.isIdentifier(prop.key) ? prop.key : null;
202
+ if (value) names.add(value.name);
203
+ }
204
+ }
205
+ }
206
+ kitBoundNamesCache.set(programPath.node, names);
207
+ return names;
208
+ }
209
+ function isKitComponentTagName(path2) {
210
+ const name = path2.node.name;
211
+ let head = null;
212
+ if (t.isJSXIdentifier(name)) {
213
+ head = name.name;
214
+ } else if (t.isJSXMemberExpression(name)) {
215
+ let cur = name;
216
+ while (t.isJSXMemberExpression(cur)) cur = cur.object;
217
+ if (t.isJSXIdentifier(cur)) head = cur.name;
218
+ }
219
+ if (!head || !/^[A-Z]/.test(head)) return false;
220
+ if (head === "Kit") return true;
221
+ const programPath = path2.scope.getProgramParent().path;
222
+ if (programPath.isProgram() && computeKitBoundNames(programPath).has(head)) return true;
223
+ const binding = path2.scope.getBinding(head);
224
+ if (binding) {
225
+ const bp = binding.path;
226
+ const isImport = bp.isImportSpecifier() || bp.isImportDefaultSpecifier() || bp.isImportNamespaceSpecifier();
227
+ if (isImport) {
228
+ const decl = bp.parentPath;
229
+ if (decl?.isImportDeclaration() && /kit-runtime/.test(decl.node.source.value)) return true;
230
+ }
231
+ }
232
+ return false;
233
+ }
234
+ function computeLockReason(isKitOrigin, isChrome, dynamicType) {
178
235
  if (isKitOrigin) return "KIT_INTERNAL";
179
236
  if (isChrome) return "CHROME_STRUCTURAL";
180
237
  if (dynamicType === "ARRAY") return "DYNAMIC_ARRAY";
181
238
  if (dynamicType === "CONDITIONAL") return "DYNAMIC_CONDITIONAL";
182
- if (containerKind === "expression") return "EXPRESSION_CONTAINER";
183
239
  return void 0;
184
240
  }
185
241
  function isMovable(path2) {
@@ -829,6 +885,10 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
829
885
  }
830
886
  }
831
887
  const vid = readVidAttr(path2.node.attributes);
888
+ if (!vid && onMissingVid && !missingVidWarned) {
889
+ missingVidWarned = true;
890
+ onMissingVid({ file, line, col, componentName, instrumented: allowLegacyIds });
891
+ }
832
892
  if (!vid && !allowLegacyIds) return;
833
893
  const nodeId = vid ?? computeNodeId(file, line, col, componentName);
834
894
  const isKitOrigin = origin === "kit" || hasSlotAttr;
@@ -856,7 +916,8 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
856
916
  const dynamicType = computeDynamicType(path2);
857
917
  const isChrome = computeIsChrome(file, path2);
858
918
  const containerKind = computeContainerKind(path2);
859
- const lockReason = computeLockReason(isKitOrigin, isChrome, dynamicType, containerKind);
919
+ const isKitComponentContainer = isKitComponentTagName(path2);
920
+ const lockReason = computeLockReason(isKitOrigin, isChrome, dynamicType);
860
921
  metaObj.properties.push(
861
922
  t.objectProperty(t.identifier("vid"), t.stringLiteral(vid)),
862
923
  t.objectProperty(t.identifier("isKitOrigin"), t.booleanLiteral(isKitOrigin)),
@@ -864,6 +925,11 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
864
925
  t.objectProperty(t.identifier("isChrome"), t.booleanLiteral(isChrome)),
865
926
  t.objectProperty(t.identifier("containerKind"), t.stringLiteral(containerKind))
866
927
  );
928
+ if (isKitComponentContainer) {
929
+ metaObj.properties.push(
930
+ t.objectProperty(t.identifier("isKitContainer"), t.booleanLiteral(true))
931
+ );
932
+ }
867
933
  if (lockReason) {
868
934
  metaObj.properties.push(
869
935
  t.objectProperty(t.identifier("lockReason"), t.stringLiteral(lockReason))
@@ -4235,6 +4235,7 @@ function isNonDroppableNodeMeta(meta) {
4235
4235
  if (meta.containerKind && meta.containerKind !== "plain") return true;
4236
4236
  if (meta.isChrome) return true;
4237
4237
  if (meta.isKitOrigin) return true;
4238
+ if (meta.isKitContainer) return true;
4238
4239
  return false;
4239
4240
  }
4240
4241
  function isNonDraggableNodeMeta(meta) {
@@ -4261,26 +4262,37 @@ function collectSubtreeIds(rootId, projection) {
4261
4262
  }
4262
4263
  function computeDroppableSet(sourceId, projection, nodeMap) {
4263
4264
  const excluded = collectSubtreeIds(sourceId, projection);
4265
+ const sourceFile = nodeMap.get(sourceId)?.editorMeta?.file;
4264
4266
  const droppable = /* @__PURE__ */ new Set();
4265
4267
  for (const containerId of projection.containerIndex.keys()) {
4266
4268
  if (excluded.has(containerId)) continue;
4267
4269
  if (isStructuralContainer(containerId, nodeMap)) continue;
4268
4270
  if (isNonDroppableNodeMeta(nodeMap.get(containerId)?.editorMeta)) continue;
4271
+ const containerFile = nodeMap.get(containerId)?.editorMeta?.file;
4272
+ if (sourceFile && containerFile && containerFile !== sourceFile) continue;
4269
4273
  droppable.add(containerId);
4270
4274
  }
4271
4275
  return droppable;
4272
4276
  }
4273
- function buildBlockedNodeMetaContainerIds(projection, nodeMap) {
4277
+ function buildBlockedNodeMetaContainerIds(projection, nodeMap, sourceId) {
4278
+ const sourceFile = sourceId ? nodeMap.get(sourceId)?.editorMeta?.file : void 0;
4274
4279
  const blocked = /* @__PURE__ */ new Set();
4275
4280
  for (const containerId of projection.containerIndex.keys()) {
4276
4281
  if (isNonDroppableNodeMeta(nodeMap.get(containerId)?.editorMeta)) {
4277
4282
  blocked.add(containerId);
4283
+ continue;
4284
+ }
4285
+ const containerFile = nodeMap.get(containerId)?.editorMeta?.file;
4286
+ if (sourceFile && containerFile && containerFile !== sourceFile) {
4287
+ blocked.add(containerId);
4278
4288
  }
4279
4289
  }
4280
4290
  return blocked;
4281
4291
  }
4282
4292
  function resolveRefusalCode(meta, fallback) {
4283
- return meta?.lockReason ?? fallback;
4293
+ if (meta?.lockReason) return meta.lockReason;
4294
+ if (meta?.isKitContainer) return "KIT_INTERNAL";
4295
+ return fallback;
4284
4296
  }
4285
4297
  function buildBlockedStructuralContainerIds(projection, nodeMap, sourceContainerId) {
4286
4298
  const blocked = /* @__PURE__ */ new Set();
@@ -4586,6 +4598,15 @@ function resolveVidFromElement(el) {
4586
4598
  const key2 = getNodeKeyFromElement(el);
4587
4599
  return VID_PATTERN.test(key2) ? key2 : null;
4588
4600
  }
4601
+ function resolveVidForScannedNode(nodeId, nodeMap, fallbackEl) {
4602
+ const scannedVid = nodeId ? nodeMap.get(nodeId)?.editorMeta?.vid : void 0;
4603
+ if (scannedVid && VID_PATTERN.test(scannedVid)) return scannedVid;
4604
+ return fallbackEl ? resolveVidFromElement(fallbackEl) : null;
4605
+ }
4606
+ function resolveVidForScannedNodeStrict(nodeId, nodeMap) {
4607
+ const scannedVid = nodeId ? nodeMap.get(nodeId)?.editorMeta?.vid : void 0;
4608
+ return scannedVid && VID_PATTERN.test(scannedVid) ? scannedVid : null;
4609
+ }
4589
4610
  function getInspectorRefFromElement(el) {
4590
4611
  const resolved = resolveDragSurface(el);
4591
4612
  const host = resolved.host ?? el;
@@ -8282,12 +8303,12 @@ function useDragVisualLoop({
8282
8303
 
8283
8304
  // src/client/dnd/design-mode/useDragLifecycle.ts
8284
8305
  var import_react13 = require("react");
8285
- function emitRefused(code, cause, element) {
8306
+ function emitRefused(code, cause, vid) {
8286
8307
  dispatchRuntimeEvent({
8287
8308
  type: "drag-refused",
8288
8309
  code,
8289
8310
  cause,
8290
- vid: element ? resolveVidFromElement(element) : null
8311
+ vid
8291
8312
  });
8292
8313
  }
8293
8314
  function resolveLaneAllowedContainers(anchorElement, srcContainerId) {
@@ -8361,7 +8382,8 @@ function recordCommittedMove(args) {
8361
8382
  sourceLaneSnapshot,
8362
8383
  targetLaneSnapshot,
8363
8384
  resolveNodeElement,
8364
- recordMoveChange
8385
+ recordMoveChange,
8386
+ nodeMap
8365
8387
  } = args;
8366
8388
  const sourceLaneIdentitySnapshot = captureCommitLaneIdentitySnapshot(
8367
8389
  sourceLaneSnapshot,
@@ -8406,10 +8428,10 @@ function recordCommittedMove(args) {
8406
8428
  });
8407
8429
  const componentName = getEditorMeta(anchorEl)?.componentName;
8408
8430
  const operationId = `${command.at}:${anchorNodeId}`;
8409
- const targetVid = resolveVidFromElement(selectedEl);
8410
8431
  const targetContainerId = command.to.parentNodeId ?? command.to.laneContainerId;
8411
8432
  const targetContainerEl = targetContainerId ? resolveNodeElement(targetContainerId) : null;
8412
- const containerVid = targetContainerEl ? resolveVidFromElement(targetContainerEl) : null;
8433
+ const targetVid = resolveVidForScannedNode(selectedNodeId, nodeMap, selectedEl);
8434
+ const containerVid = resolveVidForScannedNode(targetContainerId, nodeMap, targetContainerEl);
8413
8435
  const binding = resolveRowBinding(selectedEl);
8414
8436
  const beforePayload = buildMovePayloadWithEffectiveIdentities({
8415
8437
  placement: command.from,
@@ -8556,7 +8578,7 @@ function useDragLifecycle({
8556
8578
  emitRefused(
8557
8579
  resolveRefusalCode(found.editorMeta, "GATE_REJECT"),
8558
8580
  "Node is not draggable (dynamic render, chrome, or kit-origin).",
8559
- found.element
8581
+ resolveVidForScannedNode(activeId, refs.nodeMapRef.current, found.element)
8560
8582
  );
8561
8583
  return;
8562
8584
  }
@@ -8585,7 +8607,11 @@ function useDragLifecycle({
8585
8607
  emitRefused(
8586
8608
  resolveRefusalCode(anchorScanned?.editorMeta, "GATE_REJECT"),
8587
8609
  "Resolved drag anchor is not draggable.",
8588
- anchorScanned?.element ?? found.element
8610
+ resolveVidForScannedNode(
8611
+ anchor.anchorNodeId,
8612
+ refs.nodeMapRef.current,
8613
+ anchorScanned?.element ?? found.element
8614
+ )
8589
8615
  );
8590
8616
  return;
8591
8617
  }
@@ -8594,14 +8620,14 @@ function useDragLifecycle({
8594
8620
  const sourceCommitLane = getCommitLaneSnapshot(srcContainerId);
8595
8621
  const startPosition = getCurrentCommitPlacement(anchorNodeId, srcContainerId);
8596
8622
  const blockedContainerIds = buildBlockedStructuralContainerIds(proj, refs.nodeMapRef.current, srcContainerId);
8597
- for (const id of buildBlockedNodeMetaContainerIds(proj, refs.nodeMapRef.current)) {
8623
+ for (const id of buildBlockedNodeMetaContainerIds(proj, refs.nodeMapRef.current, anchorNodeId)) {
8598
8624
  blockedContainerIds.add(id);
8599
8625
  }
8600
8626
  const droppableSet = computeDroppableSet(anchorNodeId, proj, refs.nodeMapRef.current);
8601
8627
  refs.droppableContainerIdsRef.current = droppableSet;
8602
8628
  dispatchRuntimeEvent({
8603
8629
  type: "drag-started",
8604
- targetVid: resolveVidFromElement(anchorScanned.element),
8630
+ targetVid: resolveVidForScannedNode(anchorNodeId, refs.nodeMapRef.current, anchorScanned.element),
8605
8631
  droppable: Array.from(droppableSet)
8606
8632
  });
8607
8633
  const engineOptions = buildDragIntentEngineOptions(anchorScanned.element, srcContainerId, blockedContainerIds);
@@ -8679,11 +8705,10 @@ function useDragLifecycle({
8679
8705
  if (dropTargetId && !refs.droppableContainerIdsRef.current?.has(dropTargetId)) {
8680
8706
  const targetContainerEl = resolveNodeElement(dropTargetId);
8681
8707
  const targetMeta = refs.nodeMapRef.current.get(dropTargetId)?.editorMeta;
8682
- const fallbackCode = targetMeta?.containerKind === "expression" ? "EXPRESSION_CONTAINER" : "CONTAINER_NOT_PLAIN";
8683
8708
  emitRefused(
8684
- resolveRefusalCode(targetMeta, fallbackCode),
8709
+ resolveRefusalCode(targetMeta, "CONTAINER_NOT_PLAIN"),
8685
8710
  "Drop target is outside the droppable set for this node.",
8686
- targetContainerEl
8711
+ resolveVidForScannedNode(dropTargetId, refs.nodeMapRef.current, targetContainerEl)
8687
8712
  );
8688
8713
  clearDragState();
8689
8714
  syncHistoryAvailability();
@@ -8749,7 +8774,8 @@ function useDragLifecycle({
8749
8774
  sourceLaneSnapshot,
8750
8775
  targetLaneSnapshot,
8751
8776
  resolveNodeElement,
8752
- recordMoveChange
8777
+ recordMoveChange,
8778
+ nodeMap: refs.nodeMapRef.current
8753
8779
  });
8754
8780
  }
8755
8781
  }
@@ -8900,7 +8926,7 @@ function useResizeSession({
8900
8926
  return;
8901
8927
  }
8902
8928
  const inspectorRef = getInspectorRefFromElement(element);
8903
- const targetVid = resolveVidFromElement(element);
8929
+ const targetVid = resolveVidForScannedNode(targetNodeId, refs.nodeMapRef.current, element);
8904
8930
  const resizeCmd = {
8905
8931
  type: "resize",
8906
8932
  mode,
@@ -9150,7 +9176,7 @@ function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, s
9150
9176
  };
9151
9177
  }
9152
9178
  const operationId = `${insertCommand.at}:${nodeId}`;
9153
- const containerVid = containerEl ? resolveVidFromElement(containerEl) : null;
9179
+ const containerVid = resolveVidForScannedNodeStrict(intent.containerId, refs.nodeMapRef.current);
9154
9180
  const insertedVid = resolveVidFromElement(newElement);
9155
9181
  useDesignModeStore.getState().recordInsertChange({
9156
9182
  operationId,
@@ -9992,8 +10018,14 @@ function isPreviewOrigin(origin) {
9992
10018
 
9993
10019
  // src/client/inject-inspector/injectInspector.ts
9994
10020
  var DEFAULT_SCRIPT_ID = "archie-inspector-script";
9995
- var REMOTE_INSPECTOR_SCRIPT_URL = "https://pub-bf238c278d9644b39ec34ecaca1d315c.r2.dev/inspector.standalone.js";
9996
- function getInspectorScriptUrl(base, cacheBust = true) {
10021
+ var R2_INSPECTOR_BASE_URL = "https://pub-bf238c278d9644b39ec34ecaca1d315c.r2.dev";
10022
+ function readBuildVersion() {
10023
+ return "0.1.3" ? "0.1.3" : null;
10024
+ }
10025
+ var REMOTE_INSPECTOR_VERSION = readBuildVersion();
10026
+ var isRemoteInspectorUrlVersioned = REMOTE_INSPECTOR_VERSION !== null;
10027
+ var REMOTE_INSPECTOR_SCRIPT_URL = REMOTE_INSPECTOR_VERSION ? `${R2_INSPECTOR_BASE_URL}/inspector.standalone@${REMOTE_INSPECTOR_VERSION}.js` : `${R2_INSPECTOR_BASE_URL}/inspector.standalone.js`;
10028
+ function getInspectorScriptUrl(base, cacheBust) {
9997
10029
  const separator = base.includes("?") ? "&" : "?";
9998
10030
  return cacheBust ? `${base}${separator}h=${Date.now()}` : base;
9999
10031
  }
@@ -10049,7 +10081,8 @@ function injectInspector(opts = {}) {
10049
10081
  }
10050
10082
  }
10051
10083
  const useLocal = opts.scriptSource === "local";
10052
- const scriptUrl = useLocal ? opts.localScriptUrl ?? "/_archie/inspector.js" : getInspectorScriptUrl(opts.scriptUrl ?? REMOTE_INSPECTOR_SCRIPT_URL, true);
10084
+ const usingDefaultVersionedUrl = opts.scriptUrl === void 0 && isRemoteInspectorUrlVersioned;
10085
+ const scriptUrl = useLocal ? opts.localScriptUrl ?? "/_archie/inspector.js" : getInspectorScriptUrl(opts.scriptUrl ?? REMOTE_INSPECTOR_SCRIPT_URL, !usingDefaultVersionedUrl);
10053
10086
  const script = document.createElement("script");
10054
10087
  script.id = id;
10055
10088
  script.src = scriptUrl;
@@ -4200,6 +4200,7 @@ function isNonDroppableNodeMeta(meta) {
4200
4200
  if (meta.containerKind && meta.containerKind !== "plain") return true;
4201
4201
  if (meta.isChrome) return true;
4202
4202
  if (meta.isKitOrigin) return true;
4203
+ if (meta.isKitContainer) return true;
4203
4204
  return false;
4204
4205
  }
4205
4206
  function isNonDraggableNodeMeta(meta) {
@@ -4226,26 +4227,37 @@ function collectSubtreeIds(rootId, projection) {
4226
4227
  }
4227
4228
  function computeDroppableSet(sourceId, projection, nodeMap) {
4228
4229
  const excluded = collectSubtreeIds(sourceId, projection);
4230
+ const sourceFile = nodeMap.get(sourceId)?.editorMeta?.file;
4229
4231
  const droppable = /* @__PURE__ */ new Set();
4230
4232
  for (const containerId of projection.containerIndex.keys()) {
4231
4233
  if (excluded.has(containerId)) continue;
4232
4234
  if (isStructuralContainer(containerId, nodeMap)) continue;
4233
4235
  if (isNonDroppableNodeMeta(nodeMap.get(containerId)?.editorMeta)) continue;
4236
+ const containerFile = nodeMap.get(containerId)?.editorMeta?.file;
4237
+ if (sourceFile && containerFile && containerFile !== sourceFile) continue;
4234
4238
  droppable.add(containerId);
4235
4239
  }
4236
4240
  return droppable;
4237
4241
  }
4238
- function buildBlockedNodeMetaContainerIds(projection, nodeMap) {
4242
+ function buildBlockedNodeMetaContainerIds(projection, nodeMap, sourceId) {
4243
+ const sourceFile = sourceId ? nodeMap.get(sourceId)?.editorMeta?.file : void 0;
4239
4244
  const blocked = /* @__PURE__ */ new Set();
4240
4245
  for (const containerId of projection.containerIndex.keys()) {
4241
4246
  if (isNonDroppableNodeMeta(nodeMap.get(containerId)?.editorMeta)) {
4242
4247
  blocked.add(containerId);
4248
+ continue;
4249
+ }
4250
+ const containerFile = nodeMap.get(containerId)?.editorMeta?.file;
4251
+ if (sourceFile && containerFile && containerFile !== sourceFile) {
4252
+ blocked.add(containerId);
4243
4253
  }
4244
4254
  }
4245
4255
  return blocked;
4246
4256
  }
4247
4257
  function resolveRefusalCode(meta, fallback) {
4248
- return meta?.lockReason ?? fallback;
4258
+ if (meta?.lockReason) return meta.lockReason;
4259
+ if (meta?.isKitContainer) return "KIT_INTERNAL";
4260
+ return fallback;
4249
4261
  }
4250
4262
  function buildBlockedStructuralContainerIds(projection, nodeMap, sourceContainerId) {
4251
4263
  const blocked = /* @__PURE__ */ new Set();
@@ -4551,6 +4563,15 @@ function resolveVidFromElement(el) {
4551
4563
  const key2 = getNodeKeyFromElement(el);
4552
4564
  return VID_PATTERN.test(key2) ? key2 : null;
4553
4565
  }
4566
+ function resolveVidForScannedNode(nodeId, nodeMap, fallbackEl) {
4567
+ const scannedVid = nodeId ? nodeMap.get(nodeId)?.editorMeta?.vid : void 0;
4568
+ if (scannedVid && VID_PATTERN.test(scannedVid)) return scannedVid;
4569
+ return fallbackEl ? resolveVidFromElement(fallbackEl) : null;
4570
+ }
4571
+ function resolveVidForScannedNodeStrict(nodeId, nodeMap) {
4572
+ const scannedVid = nodeId ? nodeMap.get(nodeId)?.editorMeta?.vid : void 0;
4573
+ return scannedVid && VID_PATTERN.test(scannedVid) ? scannedVid : null;
4574
+ }
4554
4575
  function getInspectorRefFromElement(el) {
4555
4576
  const resolved = resolveDragSurface(el);
4556
4577
  const host = resolved.host ?? el;
@@ -8247,12 +8268,12 @@ function useDragVisualLoop({
8247
8268
 
8248
8269
  // src/client/dnd/design-mode/useDragLifecycle.ts
8249
8270
  import { useState as useState5, useCallback as useCallback6 } from "react";
8250
- function emitRefused(code, cause, element) {
8271
+ function emitRefused(code, cause, vid) {
8251
8272
  dispatchRuntimeEvent({
8252
8273
  type: "drag-refused",
8253
8274
  code,
8254
8275
  cause,
8255
- vid: element ? resolveVidFromElement(element) : null
8276
+ vid
8256
8277
  });
8257
8278
  }
8258
8279
  function resolveLaneAllowedContainers(anchorElement, srcContainerId) {
@@ -8326,7 +8347,8 @@ function recordCommittedMove(args) {
8326
8347
  sourceLaneSnapshot,
8327
8348
  targetLaneSnapshot,
8328
8349
  resolveNodeElement,
8329
- recordMoveChange
8350
+ recordMoveChange,
8351
+ nodeMap
8330
8352
  } = args;
8331
8353
  const sourceLaneIdentitySnapshot = captureCommitLaneIdentitySnapshot(
8332
8354
  sourceLaneSnapshot,
@@ -8371,10 +8393,10 @@ function recordCommittedMove(args) {
8371
8393
  });
8372
8394
  const componentName = getEditorMeta(anchorEl)?.componentName;
8373
8395
  const operationId = `${command.at}:${anchorNodeId}`;
8374
- const targetVid = resolveVidFromElement(selectedEl);
8375
8396
  const targetContainerId = command.to.parentNodeId ?? command.to.laneContainerId;
8376
8397
  const targetContainerEl = targetContainerId ? resolveNodeElement(targetContainerId) : null;
8377
- const containerVid = targetContainerEl ? resolveVidFromElement(targetContainerEl) : null;
8398
+ const targetVid = resolveVidForScannedNode(selectedNodeId, nodeMap, selectedEl);
8399
+ const containerVid = resolveVidForScannedNode(targetContainerId, nodeMap, targetContainerEl);
8378
8400
  const binding = resolveRowBinding(selectedEl);
8379
8401
  const beforePayload = buildMovePayloadWithEffectiveIdentities({
8380
8402
  placement: command.from,
@@ -8521,7 +8543,7 @@ function useDragLifecycle({
8521
8543
  emitRefused(
8522
8544
  resolveRefusalCode(found.editorMeta, "GATE_REJECT"),
8523
8545
  "Node is not draggable (dynamic render, chrome, or kit-origin).",
8524
- found.element
8546
+ resolveVidForScannedNode(activeId, refs.nodeMapRef.current, found.element)
8525
8547
  );
8526
8548
  return;
8527
8549
  }
@@ -8550,7 +8572,11 @@ function useDragLifecycle({
8550
8572
  emitRefused(
8551
8573
  resolveRefusalCode(anchorScanned?.editorMeta, "GATE_REJECT"),
8552
8574
  "Resolved drag anchor is not draggable.",
8553
- anchorScanned?.element ?? found.element
8575
+ resolveVidForScannedNode(
8576
+ anchor.anchorNodeId,
8577
+ refs.nodeMapRef.current,
8578
+ anchorScanned?.element ?? found.element
8579
+ )
8554
8580
  );
8555
8581
  return;
8556
8582
  }
@@ -8559,14 +8585,14 @@ function useDragLifecycle({
8559
8585
  const sourceCommitLane = getCommitLaneSnapshot(srcContainerId);
8560
8586
  const startPosition = getCurrentCommitPlacement(anchorNodeId, srcContainerId);
8561
8587
  const blockedContainerIds = buildBlockedStructuralContainerIds(proj, refs.nodeMapRef.current, srcContainerId);
8562
- for (const id of buildBlockedNodeMetaContainerIds(proj, refs.nodeMapRef.current)) {
8588
+ for (const id of buildBlockedNodeMetaContainerIds(proj, refs.nodeMapRef.current, anchorNodeId)) {
8563
8589
  blockedContainerIds.add(id);
8564
8590
  }
8565
8591
  const droppableSet = computeDroppableSet(anchorNodeId, proj, refs.nodeMapRef.current);
8566
8592
  refs.droppableContainerIdsRef.current = droppableSet;
8567
8593
  dispatchRuntimeEvent({
8568
8594
  type: "drag-started",
8569
- targetVid: resolveVidFromElement(anchorScanned.element),
8595
+ targetVid: resolveVidForScannedNode(anchorNodeId, refs.nodeMapRef.current, anchorScanned.element),
8570
8596
  droppable: Array.from(droppableSet)
8571
8597
  });
8572
8598
  const engineOptions = buildDragIntentEngineOptions(anchorScanned.element, srcContainerId, blockedContainerIds);
@@ -8644,11 +8670,10 @@ function useDragLifecycle({
8644
8670
  if (dropTargetId && !refs.droppableContainerIdsRef.current?.has(dropTargetId)) {
8645
8671
  const targetContainerEl = resolveNodeElement(dropTargetId);
8646
8672
  const targetMeta = refs.nodeMapRef.current.get(dropTargetId)?.editorMeta;
8647
- const fallbackCode = targetMeta?.containerKind === "expression" ? "EXPRESSION_CONTAINER" : "CONTAINER_NOT_PLAIN";
8648
8673
  emitRefused(
8649
- resolveRefusalCode(targetMeta, fallbackCode),
8674
+ resolveRefusalCode(targetMeta, "CONTAINER_NOT_PLAIN"),
8650
8675
  "Drop target is outside the droppable set for this node.",
8651
- targetContainerEl
8676
+ resolveVidForScannedNode(dropTargetId, refs.nodeMapRef.current, targetContainerEl)
8652
8677
  );
8653
8678
  clearDragState();
8654
8679
  syncHistoryAvailability();
@@ -8714,7 +8739,8 @@ function useDragLifecycle({
8714
8739
  sourceLaneSnapshot,
8715
8740
  targetLaneSnapshot,
8716
8741
  resolveNodeElement,
8717
- recordMoveChange
8742
+ recordMoveChange,
8743
+ nodeMap: refs.nodeMapRef.current
8718
8744
  });
8719
8745
  }
8720
8746
  }
@@ -8865,7 +8891,7 @@ function useResizeSession({
8865
8891
  return;
8866
8892
  }
8867
8893
  const inspectorRef = getInspectorRefFromElement(element);
8868
- const targetVid = resolveVidFromElement(element);
8894
+ const targetVid = resolveVidForScannedNode(targetNodeId, refs.nodeMapRef.current, element);
8869
8895
  const resizeCmd = {
8870
8896
  type: "resize",
8871
8897
  mode,
@@ -9115,7 +9141,7 @@ function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, s
9115
9141
  };
9116
9142
  }
9117
9143
  const operationId = `${insertCommand.at}:${nodeId}`;
9118
- const containerVid = containerEl ? resolveVidFromElement(containerEl) : null;
9144
+ const containerVid = resolveVidForScannedNodeStrict(intent.containerId, refs.nodeMapRef.current);
9119
9145
  const insertedVid = resolveVidFromElement(newElement);
9120
9146
  useDesignModeStore.getState().recordInsertChange({
9121
9147
  operationId,
@@ -9957,8 +9983,14 @@ function isPreviewOrigin(origin) {
9957
9983
 
9958
9984
  // src/client/inject-inspector/injectInspector.ts
9959
9985
  var DEFAULT_SCRIPT_ID = "archie-inspector-script";
9960
- var REMOTE_INSPECTOR_SCRIPT_URL = "https://pub-bf238c278d9644b39ec34ecaca1d315c.r2.dev/inspector.standalone.js";
9961
- function getInspectorScriptUrl(base, cacheBust = true) {
9986
+ var R2_INSPECTOR_BASE_URL = "https://pub-bf238c278d9644b39ec34ecaca1d315c.r2.dev";
9987
+ function readBuildVersion() {
9988
+ return "0.1.3" ? "0.1.3" : null;
9989
+ }
9990
+ var REMOTE_INSPECTOR_VERSION = readBuildVersion();
9991
+ var isRemoteInspectorUrlVersioned = REMOTE_INSPECTOR_VERSION !== null;
9992
+ var REMOTE_INSPECTOR_SCRIPT_URL = REMOTE_INSPECTOR_VERSION ? `${R2_INSPECTOR_BASE_URL}/inspector.standalone@${REMOTE_INSPECTOR_VERSION}.js` : `${R2_INSPECTOR_BASE_URL}/inspector.standalone.js`;
9993
+ function getInspectorScriptUrl(base, cacheBust) {
9962
9994
  const separator = base.includes("?") ? "&" : "?";
9963
9995
  return cacheBust ? `${base}${separator}h=${Date.now()}` : base;
9964
9996
  }
@@ -10014,7 +10046,8 @@ function injectInspector(opts = {}) {
10014
10046
  }
10015
10047
  }
10016
10048
  const useLocal = opts.scriptSource === "local";
10017
- const scriptUrl = useLocal ? opts.localScriptUrl ?? "/_archie/inspector.js" : getInspectorScriptUrl(opts.scriptUrl ?? REMOTE_INSPECTOR_SCRIPT_URL, true);
10049
+ const usingDefaultVersionedUrl = opts.scriptUrl === void 0 && isRemoteInspectorUrlVersioned;
10050
+ const scriptUrl = useLocal ? opts.localScriptUrl ?? "/_archie/inspector.js" : getInspectorScriptUrl(opts.scriptUrl ?? REMOTE_INSPECTOR_SCRIPT_URL, !usingDefaultVersionedUrl);
10018
10051
  const script = document.createElement("script");
10019
10052
  script.id = id;
10020
10053
  script.src = scriptUrl;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  meaningfulChildren
3
- } from "./chunk-THKKWDMJ.mjs";
3
+ } from "./chunk-U4KG6UDY.mjs";
4
4
 
5
5
  // src/babel-plugin-collection-binding.ts
6
6
  import { VISITOR_KEYS } from "@babel/types";
package/dist/index.d.mts CHANGED
@@ -165,6 +165,23 @@ interface EditorMetaPluginOptions {
165
165
  * @default true
166
166
  */
167
167
  allowLegacyIds?: boolean;
168
+ /**
169
+ * Called at most once per file, the first time a `JSXOpeningElement` has
170
+ * no well-formed `data-vid`. Signal only — never itself changes
171
+ * instrumentation. `instrumented` reports what THIS element gets right
172
+ * after the callback returns: `true` when it falls back to legacy
173
+ * `file:line:col:componentName` addressing (`allowLegacyIds` true, the
174
+ * default), `false` when the plugin declines to instrument it at all
175
+ * (`allowLegacyIds: false`) — the callback fires before that decision, so
176
+ * a caller cannot infer it from call order alone.
177
+ */
178
+ onMissingVid?: (info: {
179
+ file: string;
180
+ line: number;
181
+ col: number;
182
+ componentName: string;
183
+ instrumented: boolean;
184
+ }) => void;
168
185
  }
169
186
  declare function babelPluginEditorMeta({ types: t }: {
170
187
  types: typeof types;
@@ -644,6 +661,14 @@ interface EditorMeta {
644
661
  * writable, static, non-chrome, non-kit element.
645
662
  */
646
663
  lockReason?: 'KIT_INTERNAL' | 'DYNAMIC_ARRAY' | 'DYNAMIC_CONDITIONAL' | 'CHROME_STRUCTURAL' | 'EXPRESSION_CONTAINER';
664
+ /**
665
+ * `true` when this element's own tag is a Kit component instance
666
+ * (`isKitComponentTagName` in `babel-plugin-editor-meta.ts`). Devtools-local
667
+ * only, not in the `.strict()` NodeMeta protocol schema, and never folded
668
+ * into `isKitOrigin`/`lockReason` — it blocks this element as a drop
669
+ * CONTAINER only, not the element's own draggability/inspectability.
670
+ */
671
+ isKitContainer?: boolean;
647
672
  }
648
673
 
649
674
  interface ArchieDevToolsOptions {
package/dist/index.d.ts CHANGED
@@ -165,6 +165,23 @@ interface EditorMetaPluginOptions {
165
165
  * @default true
166
166
  */
167
167
  allowLegacyIds?: boolean;
168
+ /**
169
+ * Called at most once per file, the first time a `JSXOpeningElement` has
170
+ * no well-formed `data-vid`. Signal only — never itself changes
171
+ * instrumentation. `instrumented` reports what THIS element gets right
172
+ * after the callback returns: `true` when it falls back to legacy
173
+ * `file:line:col:componentName` addressing (`allowLegacyIds` true, the
174
+ * default), `false` when the plugin declines to instrument it at all
175
+ * (`allowLegacyIds: false`) — the callback fires before that decision, so
176
+ * a caller cannot infer it from call order alone.
177
+ */
178
+ onMissingVid?: (info: {
179
+ file: string;
180
+ line: number;
181
+ col: number;
182
+ componentName: string;
183
+ instrumented: boolean;
184
+ }) => void;
168
185
  }
169
186
  declare function babelPluginEditorMeta({ types: t }: {
170
187
  types: typeof types;
@@ -644,6 +661,14 @@ interface EditorMeta {
644
661
  * writable, static, non-chrome, non-kit element.
645
662
  */
646
663
  lockReason?: 'KIT_INTERNAL' | 'DYNAMIC_ARRAY' | 'DYNAMIC_CONDITIONAL' | 'CHROME_STRUCTURAL' | 'EXPRESSION_CONTAINER';
664
+ /**
665
+ * `true` when this element's own tag is a Kit component instance
666
+ * (`isKitComponentTagName` in `babel-plugin-editor-meta.ts`). Devtools-local
667
+ * only, not in the `.strict()` NodeMeta protocol schema, and never folded
668
+ * into `isKitOrigin`/`lockReason` — it blocks this element as a drop
669
+ * CONTAINER only, not the element's own draggability/inspectability.
670
+ */
671
+ isKitContainer?: boolean;
647
672
  }
648
673
 
649
674
  interface ArchieDevToolsOptions {