@archie/devtools 0.0.6 → 0.0.7

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.
@@ -0,0 +1,40 @@
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 ARCHIE_PREVIEW_ORIGIN_SUFFIXES = [
8
+ ".archie-platform.com",
9
+ ".archie.com"
10
+ ];
11
+ var LOCAL_DEV_ORIGINS = [
12
+ "http://localhost:3000",
13
+ "http://localhost:3001"
14
+ ];
15
+ function getAllowedOrigins(includeLocal = false) {
16
+ const list = [...ARCHIE_HOST_ORIGINS];
17
+ if (includeLocal) list.push(...LOCAL_DEV_ORIGINS);
18
+ return list;
19
+ }
20
+ function getAllowedOriginPatterns() {
21
+ return [...ARCHIE_PREVIEW_ORIGIN_SUFFIXES];
22
+ }
23
+ function isPreviewOrigin(origin) {
24
+ if (!origin || typeof origin !== "string") return false;
25
+ try {
26
+ const host = new URL(origin).host;
27
+ return ARCHIE_PREVIEW_ORIGIN_SUFFIXES.some((suffix) => host.endsWith(suffix));
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+
33
+ export {
34
+ ARCHIE_HOST_ORIGINS,
35
+ ARCHIE_PREVIEW_ORIGIN_SUFFIXES,
36
+ LOCAL_DEV_ORIGINS,
37
+ getAllowedOrigins,
38
+ getAllowedOriginPatterns,
39
+ isPreviewOrigin
40
+ };
@@ -1,6 +1,8 @@
1
1
  import {
2
- getAllowedOrigins
3
- } from "./chunk-6MYORGLK.mjs";
2
+ getAllowedOriginPatterns,
3
+ getAllowedOrigins,
4
+ isPreviewOrigin
5
+ } from "./chunk-DLRODACA.mjs";
4
6
 
5
7
  // src/client/inject-inspector/injectInspector.ts
6
8
  var DEFAULT_SCRIPT_ID = "archie-inspector-script";
@@ -32,12 +34,19 @@ function injectInspector(opts = {}) {
32
34
  if (allowed.length > 0) {
33
35
  win["__ARCHIE_INSPECTOR_ALLOWED_ORIGINS__"] = allowed;
34
36
  }
37
+ const patterns = getAllowedOriginPatterns();
38
+ if (patterns.length > 0) {
39
+ win["__ARCHIE_INSPECTOR_ALLOWED_ORIGIN_PATTERNS__"] = patterns;
40
+ }
35
41
  let target;
36
42
  if (opts.targetOrigin !== void 0 && opts.targetOrigin !== "*") {
37
43
  target = opts.targetOrigin || void 0;
38
44
  } else if (referrer) {
39
45
  try {
40
- target = new URL(referrer).origin;
46
+ const referrerOrigin = new URL(referrer).origin;
47
+ if (!isPreviewOrigin(referrerOrigin)) {
48
+ target = referrerOrigin;
49
+ }
41
50
  } catch {
42
51
  target = void 0;
43
52
  }
@@ -48,7 +57,7 @@ function injectInspector(opts = {}) {
48
57
  win["__ARCHIE_INSPECTOR_TARGET_ORIGIN__"] = target;
49
58
  }
50
59
  }
51
- return import("./inspector-LTHUYUGW.mjs").then((m) => {
60
+ return import("./inspector-QDRZLXRP.mjs").then((m) => {
52
61
  try {
53
62
  m.default();
54
63
  } catch (err) {
@@ -87,10 +87,33 @@ function runInspector() {
87
87
  }
88
88
  }
89
89
  var ALLOWED_ORIGINS = typeof window !== "undefined" && window.__ARCHIE_INSPECTOR_ALLOWED_ORIGINS__ || null;
90
+ var ALLOWED_ORIGIN_PATTERNS = typeof window !== "undefined" && window.__ARCHIE_INSPECTOR_ALLOWED_ORIGIN_PATTERNS__ || [];
90
91
  function isOriginAllowed(origin) {
91
92
  if (!origin) return false;
92
- if (!Array.isArray(ALLOWED_ORIGINS) || ALLOWED_ORIGINS.length === 0 || ALLOWED_ORIGINS === "*") return false;
93
- return ALLOWED_ORIGINS.indexOf(origin) !== -1;
93
+ if (Array.isArray(ALLOWED_ORIGINS) && ALLOWED_ORIGINS.length > 0 && ALLOWED_ORIGINS !== "*") {
94
+ if (ALLOWED_ORIGINS.indexOf(origin) !== -1) return true;
95
+ }
96
+ if (Array.isArray(ALLOWED_ORIGIN_PATTERNS) && ALLOWED_ORIGIN_PATTERNS.length > 0) {
97
+ try {
98
+ var host = new URL(origin).host;
99
+ for (var i = 0; i < ALLOWED_ORIGIN_PATTERNS.length; i++) {
100
+ if (host.endsWith(ALLOWED_ORIGIN_PATTERNS[i])) return true;
101
+ }
102
+ } catch (e) {
103
+ }
104
+ }
105
+ return false;
106
+ }
107
+ function isStyleValueSafe(value) {
108
+ if (value == null || typeof value !== "string") return false;
109
+ if (value.length > 1e4) return false;
110
+ var lower = value.toLowerCase();
111
+ if (lower.indexOf("javascript:") !== -1) return false;
112
+ if (lower.indexOf("expression(") !== -1) return false;
113
+ if (lower.indexOf("-moz-binding") !== -1) return false;
114
+ if (lower.indexOf("behavior") !== -1) return false;
115
+ if (lower.indexOf("vbscript:") !== -1) return false;
116
+ return true;
94
117
  }
95
118
  var SCROLL_LISTENER_OPTS = { capture: true, passive: true };
96
119
  var RESIZE_LISTENER_OPTS = { passive: true };
@@ -691,6 +714,17 @@ function runInspector() {
691
714
  property,
692
715
  value
693
716
  });
717
+ if (!property || typeof property !== "string" || property.length > 100 || !isStyleValueSafe(value)) {
718
+ inspectorWarn("[Inspector] Rejected invalid or unsafe style property/value");
719
+ postMessageToParent({
720
+ type: "STYLE_CHANGE_FAILED",
721
+ selector,
722
+ property: typeof property === "string" ? property : "",
723
+ value: value != null ? String(value).slice(0, 100) : "",
724
+ error: !isStyleValueSafe(value) ? "Invalid or unsafe style value" : "Invalid property"
725
+ });
726
+ return;
727
+ }
694
728
  let element = null;
695
729
  element = getSelectedElement();
696
730
  if (element) {
@@ -766,6 +800,7 @@ function runInspector() {
766
800
  );
767
801
  setTimeout(() => {
768
802
  try {
803
+ if (!isStyleValueSafe(value)) return;
769
804
  const retryElement = document.querySelector(selector);
770
805
  if (retryElement) {
771
806
  inspectorLog("[Inspector] Found element on retry");
@@ -858,7 +893,8 @@ function runInspector() {
858
893
  });
859
894
  return;
860
895
  }
861
- const classes = className.split(/\s+/).filter(Boolean);
896
+ var classStr = typeof className === "string" ? className.slice(0, 2e3) : "";
897
+ const classes = classStr.split(/\s+/).filter(Boolean).slice(0, 100);
862
898
  classes.forEach((cls) => {
863
899
  if (action === "remove") {
864
900
  element.classList.remove(cls);
@@ -898,6 +934,15 @@ function runInspector() {
898
934
  });
899
935
  } else if (event.data && event.data.type === "APPLY_TEXT_CHANGE") {
900
936
  const { selector, text } = event.data;
937
+ if (text != null && typeof text === "string" && text.length > 5e5) {
938
+ postMessageToParent({
939
+ type: "TEXT_CHANGE_FAILED",
940
+ selector,
941
+ text: "",
942
+ error: "Text value too long"
943
+ });
944
+ return;
945
+ }
901
946
  const element = getSelectedElement();
902
947
  if (!element) {
903
948
  postMessageToParent({
@@ -908,7 +953,7 @@ function runInspector() {
908
953
  });
909
954
  return;
910
955
  }
911
- element.textContent = text;
956
+ element.textContent = text != null ? String(text) : "";
912
957
  postMessageToParent({
913
958
  type: "TEXT_CHANGE_APPLIED",
914
959
  selector,
@@ -1116,6 +1161,10 @@ var ARCHIE_HOST_ORIGINS = [
1116
1161
  "https://app.staging.archie-platform.com",
1117
1162
  "https://app.archie.com"
1118
1163
  ];
1164
+ var ARCHIE_PREVIEW_ORIGIN_SUFFIXES = [
1165
+ ".archie-platform.com",
1166
+ ".archie.com"
1167
+ ];
1119
1168
  var LOCAL_DEV_ORIGINS = [
1120
1169
  "http://localhost:3000",
1121
1170
  "http://localhost:3001"
@@ -1125,6 +1174,18 @@ function getAllowedOrigins(includeLocal = false) {
1125
1174
  if (includeLocal) list.push(...LOCAL_DEV_ORIGINS);
1126
1175
  return list;
1127
1176
  }
1177
+ function getAllowedOriginPatterns() {
1178
+ return [...ARCHIE_PREVIEW_ORIGIN_SUFFIXES];
1179
+ }
1180
+ function isPreviewOrigin(origin) {
1181
+ if (!origin || typeof origin !== "string") return false;
1182
+ try {
1183
+ const host = new URL(origin).host;
1184
+ return ARCHIE_PREVIEW_ORIGIN_SUFFIXES.some((suffix) => host.endsWith(suffix));
1185
+ } catch {
1186
+ return false;
1187
+ }
1188
+ }
1128
1189
 
1129
1190
  // src/client/inject-inspector/injectInspector.ts
1130
1191
  var DEFAULT_SCRIPT_ID = "archie-inspector-script";
@@ -1156,12 +1217,19 @@ function injectInspector(opts = {}) {
1156
1217
  if (allowed.length > 0) {
1157
1218
  win["__ARCHIE_INSPECTOR_ALLOWED_ORIGINS__"] = allowed;
1158
1219
  }
1220
+ const patterns = getAllowedOriginPatterns();
1221
+ if (patterns.length > 0) {
1222
+ win["__ARCHIE_INSPECTOR_ALLOWED_ORIGIN_PATTERNS__"] = patterns;
1223
+ }
1159
1224
  let target;
1160
1225
  if (opts.targetOrigin !== void 0 && opts.targetOrigin !== "*") {
1161
1226
  target = opts.targetOrigin || void 0;
1162
1227
  } else if (referrer) {
1163
1228
  try {
1164
- target = new URL(referrer).origin;
1229
+ const referrerOrigin = new URL(referrer).origin;
1230
+ if (!isPreviewOrigin(referrerOrigin)) {
1231
+ target = referrerOrigin;
1232
+ }
1165
1233
  } catch {
1166
1234
  target = void 0;
1167
1235
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  injectInspector
3
- } from "../../chunk-NYVHR4QL.mjs";
4
- import "../../chunk-6MYORGLK.mjs";
3
+ } from "../../chunk-JPNYFFBN.mjs";
4
+ import "../../chunk-DLRODACA.mjs";
5
5
 
6
6
  // src/client/inject-inspector/auto.ts
7
7
  injectInspector();
@@ -8,8 +8,10 @@ type InjectOptions = {
8
8
  */
9
9
  allowedOrigins?: string | string[];
10
10
  /**
11
- * Origin to which the inspector sends postMessage replies.
12
- * If not set and in an iframe, uses document.referrer origin.
11
+ * Origin to which the inspector sends postMessage replies (the parent window).
12
+ * If not set and in an iframe, uses document.referrer origin — except when the page
13
+ * is a preview iframe (*.previews.staging.archie-platform.com), in which case you
14
+ * must pass the parent app origin (e.g. https://app.dev.archie-platform.com).
13
15
  * "*" is not allowed.
14
16
  */
15
17
  targetOrigin?: string;
@@ -24,7 +26,10 @@ type InjectOptions = {
24
26
  * Safe to call multiple times: avoids duplicate execution by id.
25
27
  * No-op when run outside the browser (e.g. SSR).
26
28
  *
27
- * Origin restrictions are always set (never "*"): Archie host origins, and in dev optionally localhost.
29
+ * Security: Origin restrictions are always set (never "*"). We do not inject
30
+ * script via eval/Function or write HTML (innerHTML/insertAdjacentHTML).
31
+ * The inspector only accepts postMessage from allowlisted origins and
32
+ * sanitizes style values before applying to the DOM.
28
33
  *
29
34
  * @returns Promise that resolves to the marker script element, or null if not in browser / already present
30
35
  */
@@ -8,8 +8,10 @@ type InjectOptions = {
8
8
  */
9
9
  allowedOrigins?: string | string[];
10
10
  /**
11
- * Origin to which the inspector sends postMessage replies.
12
- * If not set and in an iframe, uses document.referrer origin.
11
+ * Origin to which the inspector sends postMessage replies (the parent window).
12
+ * If not set and in an iframe, uses document.referrer origin — except when the page
13
+ * is a preview iframe (*.previews.staging.archie-platform.com), in which case you
14
+ * must pass the parent app origin (e.g. https://app.dev.archie-platform.com).
13
15
  * "*" is not allowed.
14
16
  */
15
17
  targetOrigin?: string;
@@ -24,7 +26,10 @@ type InjectOptions = {
24
26
  * Safe to call multiple times: avoids duplicate execution by id.
25
27
  * No-op when run outside the browser (e.g. SSR).
26
28
  *
27
- * Origin restrictions are always set (never "*"): Archie host origins, and in dev optionally localhost.
29
+ * Security: Origin restrictions are always set (never "*"). We do not inject
30
+ * script via eval/Function or write HTML (innerHTML/insertAdjacentHTML).
31
+ * The inspector only accepts postMessage from allowlisted origins and
32
+ * sanitizes style values before applying to the DOM.
28
33
  *
29
34
  * @returns Promise that resolves to the marker script element, or null if not in browser / already present
30
35
  */
@@ -98,10 +98,33 @@ function runInspector() {
98
98
  }
99
99
  }
100
100
  var ALLOWED_ORIGINS = typeof window !== "undefined" && window.__ARCHIE_INSPECTOR_ALLOWED_ORIGINS__ || null;
101
+ var ALLOWED_ORIGIN_PATTERNS = typeof window !== "undefined" && window.__ARCHIE_INSPECTOR_ALLOWED_ORIGIN_PATTERNS__ || [];
101
102
  function isOriginAllowed(origin) {
102
103
  if (!origin) return false;
103
- if (!Array.isArray(ALLOWED_ORIGINS) || ALLOWED_ORIGINS.length === 0 || ALLOWED_ORIGINS === "*") return false;
104
- return ALLOWED_ORIGINS.indexOf(origin) !== -1;
104
+ if (Array.isArray(ALLOWED_ORIGINS) && ALLOWED_ORIGINS.length > 0 && ALLOWED_ORIGINS !== "*") {
105
+ if (ALLOWED_ORIGINS.indexOf(origin) !== -1) return true;
106
+ }
107
+ if (Array.isArray(ALLOWED_ORIGIN_PATTERNS) && ALLOWED_ORIGIN_PATTERNS.length > 0) {
108
+ try {
109
+ var host = new URL(origin).host;
110
+ for (var i = 0; i < ALLOWED_ORIGIN_PATTERNS.length; i++) {
111
+ if (host.endsWith(ALLOWED_ORIGIN_PATTERNS[i])) return true;
112
+ }
113
+ } catch (e) {
114
+ }
115
+ }
116
+ return false;
117
+ }
118
+ function isStyleValueSafe(value) {
119
+ if (value == null || typeof value !== "string") return false;
120
+ if (value.length > 1e4) return false;
121
+ var lower = value.toLowerCase();
122
+ if (lower.indexOf("javascript:") !== -1) return false;
123
+ if (lower.indexOf("expression(") !== -1) return false;
124
+ if (lower.indexOf("-moz-binding") !== -1) return false;
125
+ if (lower.indexOf("behavior") !== -1) return false;
126
+ if (lower.indexOf("vbscript:") !== -1) return false;
127
+ return true;
105
128
  }
106
129
  var SCROLL_LISTENER_OPTS = { capture: true, passive: true };
107
130
  var RESIZE_LISTENER_OPTS = { passive: true };
@@ -702,6 +725,17 @@ function runInspector() {
702
725
  property,
703
726
  value
704
727
  });
728
+ if (!property || typeof property !== "string" || property.length > 100 || !isStyleValueSafe(value)) {
729
+ inspectorWarn("[Inspector] Rejected invalid or unsafe style property/value");
730
+ postMessageToParent({
731
+ type: "STYLE_CHANGE_FAILED",
732
+ selector,
733
+ property: typeof property === "string" ? property : "",
734
+ value: value != null ? String(value).slice(0, 100) : "",
735
+ error: !isStyleValueSafe(value) ? "Invalid or unsafe style value" : "Invalid property"
736
+ });
737
+ return;
738
+ }
705
739
  let element = null;
706
740
  element = getSelectedElement();
707
741
  if (element) {
@@ -777,6 +811,7 @@ function runInspector() {
777
811
  );
778
812
  setTimeout(() => {
779
813
  try {
814
+ if (!isStyleValueSafe(value)) return;
780
815
  const retryElement = document.querySelector(selector);
781
816
  if (retryElement) {
782
817
  inspectorLog("[Inspector] Found element on retry");
@@ -869,7 +904,8 @@ function runInspector() {
869
904
  });
870
905
  return;
871
906
  }
872
- const classes = className.split(/\s+/).filter(Boolean);
907
+ var classStr = typeof className === "string" ? className.slice(0, 2e3) : "";
908
+ const classes = classStr.split(/\s+/).filter(Boolean).slice(0, 100);
873
909
  classes.forEach((cls) => {
874
910
  if (action === "remove") {
875
911
  element.classList.remove(cls);
@@ -909,6 +945,15 @@ function runInspector() {
909
945
  });
910
946
  } else if (event.data && event.data.type === "APPLY_TEXT_CHANGE") {
911
947
  const { selector, text } = event.data;
948
+ if (text != null && typeof text === "string" && text.length > 5e5) {
949
+ postMessageToParent({
950
+ type: "TEXT_CHANGE_FAILED",
951
+ selector,
952
+ text: "",
953
+ error: "Text value too long"
954
+ });
955
+ return;
956
+ }
912
957
  const element = getSelectedElement();
913
958
  if (!element) {
914
959
  postMessageToParent({
@@ -919,7 +964,7 @@ function runInspector() {
919
964
  });
920
965
  return;
921
966
  }
922
- element.textContent = text;
967
+ element.textContent = text != null ? String(text) : "";
923
968
  postMessageToParent({
924
969
  type: "TEXT_CHANGE_APPLIED",
925
970
  selector,
@@ -1134,6 +1179,10 @@ var ARCHIE_HOST_ORIGINS = [
1134
1179
  "https://app.staging.archie-platform.com",
1135
1180
  "https://app.archie.com"
1136
1181
  ];
1182
+ var ARCHIE_PREVIEW_ORIGIN_SUFFIXES = [
1183
+ ".archie-platform.com",
1184
+ ".archie.com"
1185
+ ];
1137
1186
  var LOCAL_DEV_ORIGINS = [
1138
1187
  "http://localhost:3000",
1139
1188
  "http://localhost:3001"
@@ -1143,6 +1192,18 @@ function getAllowedOrigins(includeLocal = false) {
1143
1192
  if (includeLocal) list.push(...LOCAL_DEV_ORIGINS);
1144
1193
  return list;
1145
1194
  }
1195
+ function getAllowedOriginPatterns() {
1196
+ return [...ARCHIE_PREVIEW_ORIGIN_SUFFIXES];
1197
+ }
1198
+ function isPreviewOrigin(origin) {
1199
+ if (!origin || typeof origin !== "string") return false;
1200
+ try {
1201
+ const host = new URL(origin).host;
1202
+ return ARCHIE_PREVIEW_ORIGIN_SUFFIXES.some((suffix) => host.endsWith(suffix));
1203
+ } catch {
1204
+ return false;
1205
+ }
1206
+ }
1146
1207
 
1147
1208
  // src/client/inject-inspector/injectInspector.ts
1148
1209
  var DEFAULT_SCRIPT_ID = "archie-inspector-script";
@@ -1174,12 +1235,19 @@ function injectInspector(opts = {}) {
1174
1235
  if (allowed.length > 0) {
1175
1236
  win["__ARCHIE_INSPECTOR_ALLOWED_ORIGINS__"] = allowed;
1176
1237
  }
1238
+ const patterns = getAllowedOriginPatterns();
1239
+ if (patterns.length > 0) {
1240
+ win["__ARCHIE_INSPECTOR_ALLOWED_ORIGIN_PATTERNS__"] = patterns;
1241
+ }
1177
1242
  let target;
1178
1243
  if (opts.targetOrigin !== void 0 && opts.targetOrigin !== "*") {
1179
1244
  target = opts.targetOrigin || void 0;
1180
1245
  } else if (referrer) {
1181
1246
  try {
1182
- target = new URL(referrer).origin;
1247
+ const referrerOrigin = new URL(referrer).origin;
1248
+ if (!isPreviewOrigin(referrerOrigin)) {
1249
+ target = referrerOrigin;
1250
+ }
1183
1251
  } catch {
1184
1252
  target = void 0;
1185
1253
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  injectInspector
3
- } from "../../chunk-NYVHR4QL.mjs";
4
- import "../../chunk-6MYORGLK.mjs";
3
+ } from "../../chunk-JPNYFFBN.mjs";
4
+ import "../../chunk-DLRODACA.mjs";
5
5
  export {
6
6
  injectInspector
7
7
  };
@@ -6,6 +6,11 @@
6
6
  * @see https://app.archie.com
7
7
  */
8
8
  declare const ARCHIE_HOST_ORIGINS: readonly ["https://app.dev.archie-platform.com", "https://app.staging.archie-platform.com", "https://app.archie.com"];
9
+ /**
10
+ * Origin suffix patterns for Archie preview iframes (e.g. deploy previews).
11
+ * The inspector allows any origin whose host ends with one of these suffixes,
12
+ */
13
+ declare const ARCHIE_PREVIEW_ORIGIN_SUFFIXES: readonly [".archie-platform.com", ".archie.com"];
9
14
  /**
10
15
  * Common local origins for development. Add these when testing the inspector
11
16
  * with the host running on localhost (e.g. host on :3000, preview iframe on :5173).
@@ -20,5 +25,15 @@ type ArchieHostOrigin = (typeof ARCHIE_HOST_ORIGINS)[number];
20
25
  * @param includeLocal - If true, appends LOCAL_DEV_ORIGINS for local testing
21
26
  */
22
27
  declare function getAllowedOrigins(includeLocal?: boolean): string[];
28
+ /**
29
+ * Returns origin suffix patterns for preview iframes. The inspector allows any origin
30
+ * one of these suffixes (after the protocol).
31
+ */
32
+ declare function getAllowedOriginPatterns(): string[];
33
+ /**
34
+ * Returns true if the given origin is a known Archie preview origin (e.g. deploy preview iframe).
35
+ * When the inspector runs inside a preview iframe, targetOrigin for postMessage must be
36
+ */
37
+ declare function isPreviewOrigin(origin: string): boolean;
23
38
 
24
- export { ARCHIE_HOST_ORIGINS, type ArchieHostOrigin, LOCAL_DEV_ORIGINS, getAllowedOrigins };
39
+ export { ARCHIE_HOST_ORIGINS, ARCHIE_PREVIEW_ORIGIN_SUFFIXES, type ArchieHostOrigin, LOCAL_DEV_ORIGINS, getAllowedOriginPatterns, getAllowedOrigins, isPreviewOrigin };
@@ -6,6 +6,11 @@
6
6
  * @see https://app.archie.com
7
7
  */
8
8
  declare const ARCHIE_HOST_ORIGINS: readonly ["https://app.dev.archie-platform.com", "https://app.staging.archie-platform.com", "https://app.archie.com"];
9
+ /**
10
+ * Origin suffix patterns for Archie preview iframes (e.g. deploy previews).
11
+ * The inspector allows any origin whose host ends with one of these suffixes,
12
+ */
13
+ declare const ARCHIE_PREVIEW_ORIGIN_SUFFIXES: readonly [".archie-platform.com", ".archie.com"];
9
14
  /**
10
15
  * Common local origins for development. Add these when testing the inspector
11
16
  * with the host running on localhost (e.g. host on :3000, preview iframe on :5173).
@@ -20,5 +25,15 @@ type ArchieHostOrigin = (typeof ARCHIE_HOST_ORIGINS)[number];
20
25
  * @param includeLocal - If true, appends LOCAL_DEV_ORIGINS for local testing
21
26
  */
22
27
  declare function getAllowedOrigins(includeLocal?: boolean): string[];
28
+ /**
29
+ * Returns origin suffix patterns for preview iframes. The inspector allows any origin
30
+ * one of these suffixes (after the protocol).
31
+ */
32
+ declare function getAllowedOriginPatterns(): string[];
33
+ /**
34
+ * Returns true if the given origin is a known Archie preview origin (e.g. deploy preview iframe).
35
+ * When the inspector runs inside a preview iframe, targetOrigin for postMessage must be
36
+ */
37
+ declare function isPreviewOrigin(origin: string): boolean;
23
38
 
24
- export { ARCHIE_HOST_ORIGINS, type ArchieHostOrigin, LOCAL_DEV_ORIGINS, getAllowedOrigins };
39
+ export { ARCHIE_HOST_ORIGINS, ARCHIE_PREVIEW_ORIGIN_SUFFIXES, type ArchieHostOrigin, LOCAL_DEV_ORIGINS, getAllowedOriginPatterns, getAllowedOrigins, isPreviewOrigin };
@@ -21,8 +21,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var archieOrigins_exports = {};
22
22
  __export(archieOrigins_exports, {
23
23
  ARCHIE_HOST_ORIGINS: () => ARCHIE_HOST_ORIGINS,
24
+ ARCHIE_PREVIEW_ORIGIN_SUFFIXES: () => ARCHIE_PREVIEW_ORIGIN_SUFFIXES,
24
25
  LOCAL_DEV_ORIGINS: () => LOCAL_DEV_ORIGINS,
25
- getAllowedOrigins: () => getAllowedOrigins
26
+ getAllowedOriginPatterns: () => getAllowedOriginPatterns,
27
+ getAllowedOrigins: () => getAllowedOrigins,
28
+ isPreviewOrigin: () => isPreviewOrigin
26
29
  });
27
30
  module.exports = __toCommonJS(archieOrigins_exports);
28
31
  var ARCHIE_HOST_ORIGINS = [
@@ -30,6 +33,10 @@ var ARCHIE_HOST_ORIGINS = [
30
33
  "https://app.staging.archie-platform.com",
31
34
  "https://app.archie.com"
32
35
  ];
36
+ var ARCHIE_PREVIEW_ORIGIN_SUFFIXES = [
37
+ ".archie-platform.com",
38
+ ".archie.com"
39
+ ];
33
40
  var LOCAL_DEV_ORIGINS = [
34
41
  "http://localhost:3000",
35
42
  "http://localhost:3001"
@@ -39,9 +46,24 @@ function getAllowedOrigins(includeLocal = false) {
39
46
  if (includeLocal) list.push(...LOCAL_DEV_ORIGINS);
40
47
  return list;
41
48
  }
49
+ function getAllowedOriginPatterns() {
50
+ return [...ARCHIE_PREVIEW_ORIGIN_SUFFIXES];
51
+ }
52
+ function isPreviewOrigin(origin) {
53
+ if (!origin || typeof origin !== "string") return false;
54
+ try {
55
+ const host = new URL(origin).host;
56
+ return ARCHIE_PREVIEW_ORIGIN_SUFFIXES.some((suffix) => host.endsWith(suffix));
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
42
61
  // Annotate the CommonJS export names for ESM import in node:
43
62
  0 && (module.exports = {
44
63
  ARCHIE_HOST_ORIGINS,
64
+ ARCHIE_PREVIEW_ORIGIN_SUFFIXES,
45
65
  LOCAL_DEV_ORIGINS,
46
- getAllowedOrigins
66
+ getAllowedOriginPatterns,
67
+ getAllowedOrigins,
68
+ isPreviewOrigin
47
69
  });
@@ -1,10 +1,16 @@
1
1
  import {
2
2
  ARCHIE_HOST_ORIGINS,
3
+ ARCHIE_PREVIEW_ORIGIN_SUFFIXES,
3
4
  LOCAL_DEV_ORIGINS,
4
- getAllowedOrigins
5
- } from "../chunk-6MYORGLK.mjs";
5
+ getAllowedOriginPatterns,
6
+ getAllowedOrigins,
7
+ isPreviewOrigin
8
+ } from "../chunk-DLRODACA.mjs";
6
9
  export {
7
10
  ARCHIE_HOST_ORIGINS,
11
+ ARCHIE_PREVIEW_ORIGIN_SUFFIXES,
8
12
  LOCAL_DEV_ORIGINS,
9
- getAllowedOrigins
13
+ getAllowedOriginPatterns,
14
+ getAllowedOrigins,
15
+ isPreviewOrigin
10
16
  };
@@ -72,10 +72,33 @@ function runInspector() {
72
72
  }
73
73
  }
74
74
  var ALLOWED_ORIGINS = typeof window !== "undefined" && window.__ARCHIE_INSPECTOR_ALLOWED_ORIGINS__ || null;
75
+ var ALLOWED_ORIGIN_PATTERNS = typeof window !== "undefined" && window.__ARCHIE_INSPECTOR_ALLOWED_ORIGIN_PATTERNS__ || [];
75
76
  function isOriginAllowed(origin) {
76
77
  if (!origin) return false;
77
- if (!Array.isArray(ALLOWED_ORIGINS) || ALLOWED_ORIGINS.length === 0 || ALLOWED_ORIGINS === "*") return false;
78
- return ALLOWED_ORIGINS.indexOf(origin) !== -1;
78
+ if (Array.isArray(ALLOWED_ORIGINS) && ALLOWED_ORIGINS.length > 0 && ALLOWED_ORIGINS !== "*") {
79
+ if (ALLOWED_ORIGINS.indexOf(origin) !== -1) return true;
80
+ }
81
+ if (Array.isArray(ALLOWED_ORIGIN_PATTERNS) && ALLOWED_ORIGIN_PATTERNS.length > 0) {
82
+ try {
83
+ var host = new URL(origin).host;
84
+ for (var i = 0; i < ALLOWED_ORIGIN_PATTERNS.length; i++) {
85
+ if (host.endsWith(ALLOWED_ORIGIN_PATTERNS[i])) return true;
86
+ }
87
+ } catch (e) {
88
+ }
89
+ }
90
+ return false;
91
+ }
92
+ function isStyleValueSafe(value) {
93
+ if (value == null || typeof value !== "string") return false;
94
+ if (value.length > 1e4) return false;
95
+ var lower = value.toLowerCase();
96
+ if (lower.indexOf("javascript:") !== -1) return false;
97
+ if (lower.indexOf("expression(") !== -1) return false;
98
+ if (lower.indexOf("-moz-binding") !== -1) return false;
99
+ if (lower.indexOf("behavior") !== -1) return false;
100
+ if (lower.indexOf("vbscript:") !== -1) return false;
101
+ return true;
79
102
  }
80
103
  var SCROLL_LISTENER_OPTS = { capture: true, passive: true };
81
104
  var RESIZE_LISTENER_OPTS = { passive: true };
@@ -676,6 +699,17 @@ function runInspector() {
676
699
  property,
677
700
  value
678
701
  });
702
+ if (!property || typeof property !== "string" || property.length > 100 || !isStyleValueSafe(value)) {
703
+ inspectorWarn("[Inspector] Rejected invalid or unsafe style property/value");
704
+ postMessageToParent({
705
+ type: "STYLE_CHANGE_FAILED",
706
+ selector,
707
+ property: typeof property === "string" ? property : "",
708
+ value: value != null ? String(value).slice(0, 100) : "",
709
+ error: !isStyleValueSafe(value) ? "Invalid or unsafe style value" : "Invalid property"
710
+ });
711
+ return;
712
+ }
679
713
  let element = null;
680
714
  element = getSelectedElement();
681
715
  if (element) {
@@ -751,6 +785,7 @@ function runInspector() {
751
785
  );
752
786
  setTimeout(() => {
753
787
  try {
788
+ if (!isStyleValueSafe(value)) return;
754
789
  const retryElement = document.querySelector(selector);
755
790
  if (retryElement) {
756
791
  inspectorLog("[Inspector] Found element on retry");
@@ -843,7 +878,8 @@ function runInspector() {
843
878
  });
844
879
  return;
845
880
  }
846
- const classes = className.split(/\s+/).filter(Boolean);
881
+ var classStr = typeof className === "string" ? className.slice(0, 2e3) : "";
882
+ const classes = classStr.split(/\s+/).filter(Boolean).slice(0, 100);
847
883
  classes.forEach((cls) => {
848
884
  if (action === "remove") {
849
885
  element.classList.remove(cls);
@@ -883,6 +919,15 @@ function runInspector() {
883
919
  });
884
920
  } else if (event.data && event.data.type === "APPLY_TEXT_CHANGE") {
885
921
  const { selector, text } = event.data;
922
+ if (text != null && typeof text === "string" && text.length > 5e5) {
923
+ postMessageToParent({
924
+ type: "TEXT_CHANGE_FAILED",
925
+ selector,
926
+ text: "",
927
+ error: "Text value too long"
928
+ });
929
+ return;
930
+ }
886
931
  const element = getSelectedElement();
887
932
  if (!element) {
888
933
  postMessageToParent({
@@ -893,7 +938,7 @@ function runInspector() {
893
938
  });
894
939
  return;
895
940
  }
896
- element.textContent = text;
941
+ element.textContent = text != null ? String(text) : "";
897
942
  postMessageToParent({
898
943
  type: "TEXT_CHANGE_APPLIED",
899
944
  selector,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archie/devtools",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "DevTools for Archie generated applications - Route synchronization and editor communication",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -1,21 +0,0 @@
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
- };