@playruo/embed 1.7.0 → 1.8.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/dist/index.cjs CHANGED
@@ -211,6 +211,14 @@ var PlayruoEmbed = ({
211
211
  }, []);
212
212
  const isCompatible = !isMobile && isValidChromium;
213
213
  const isReady = isCompatible ? isIframeLoaded : true;
214
+ (0, import_react.useEffect)(() => {
215
+ const iframe = iframeRef.current;
216
+ if (!iframe || iframe.getAttribute("src") === src) {
217
+ return;
218
+ }
219
+ iframe.setAttribute("credentialless", "");
220
+ iframe.src = src;
221
+ }, [iframeRef, isCompatible, src]);
214
222
  const currentState = (0, import_react.useMemo)(() => {
215
223
  if (iframeState) {
216
224
  return iframeState;
@@ -283,7 +291,7 @@ var PlayruoEmbed = ({
283
291
  embedOrigin
284
292
  );
285
293
  } catch {
286
- console.error("[PlayruoEmbed] Failed to send the password action");
294
+ console.error("[PlayruoEmbed] Failed to send iframe action");
287
295
  }
288
296
  },
289
297
  [embedOrigin, iframeRef]
@@ -806,7 +814,9 @@ var PlayruoEmbed = ({
806
814
  tryNow: handleTryNow,
807
815
  buyNow: handleBuyNow,
808
816
  canTryNow,
809
- canBuyNow: Boolean(isReady),
817
+ canBuyNow: Boolean(isReady && storeUrl),
818
+ mute: () => postPasswordAction({ action: "mute" }),
819
+ unmute: () => postPasswordAction({ action: "unmute" }),
810
820
  submitPassword: (password2) => {
811
821
  if (!password2) {
812
822
  return;
@@ -872,10 +882,8 @@ var PlayruoEmbed = ({
872
882
  "iframe",
873
883
  {
874
884
  ref: iframeRef,
875
- src,
876
885
  allow: PLAYRUO_IFRAME_ALLOW,
877
886
  className: "w-full h-[70vh] rounded-lg border",
878
- ...{ credentialless: "true" },
879
887
  sandbox: "allow-same-origin allow-scripts allow-popups allow-forms allow-presentation allow-top-navigation allow-modals allow-pointer-lock",
880
888
  title: "Playruo",
881
889
  referrerPolicy: "strict-origin-when-cross-origin",
@@ -887,8 +895,10 @@ var PlayruoEmbed = ({
887
895
  height: "100%",
888
896
  border: 0
889
897
  },
890
- onLoad: () => {
891
- setIsIframeLoaded(true);
898
+ onLoad: (event) => {
899
+ if (event.currentTarget.getAttribute("src")) {
900
+ setIsIframeLoaded(true);
901
+ }
892
902
  },
893
903
  onError: () => {
894
904
  console.error("[PlayruoEmbed] Iframe failed to load");
@@ -1043,7 +1053,7 @@ var EmbedTester = (props = {}) => {
1043
1053
  }
1044
1054
  }, [addEvent, enableConsoleLog]);
1045
1055
  const handleEvent = (0, import_react2.useCallback)((data) => {
1046
- const eventName = typeof data.event === "string" ? data.event : typeof data.name === "string" ? data.name : "unknown";
1056
+ const eventName = typeof data.name === "string" ? data.name : typeof data.event === "string" ? data.event : "unknown";
1047
1057
  addEvent(`Event received: ${eventName}`);
1048
1058
  if (enableConsoleLog) {
1049
1059
  console.log("Embed event:", data);
package/dist/index.d.cts CHANGED
@@ -1,5 +1,4 @@
1
- import { FC, ReactNode } from 'react';
2
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import React$1, { FC, ReactNode } from 'react';
3
2
 
4
3
  /**
5
4
  * iframe `allow` feature policy delegated to the Playruo player.
@@ -28,7 +27,13 @@ interface DemoCompletedPayload {
28
27
  type PlayruoEventPayload = Record<string, unknown> & {
29
28
  action?: string;
30
29
  category?: string;
30
+ /**
31
+ * @deprecated The webapp puts the event identifier on `name`. Nothing it
32
+ * posts carries `event`, so a host switching on it never matches. Kept so
33
+ * older hosts still compile.
34
+ */
31
35
  event?: string;
36
+ /** Event identifier, snake_case (`auth_ok`, `streaming`, `vmnok`). */
32
37
  name?: string;
33
38
  };
34
39
 
@@ -162,8 +167,16 @@ interface PlayruoEmbedActions {
162
167
  buyNow: () => void;
163
168
  /** Whether try now is currently available */
164
169
  canTryNow: boolean;
165
- /** Whether buy now is currently available */
170
+ /**
171
+ * Whether buy now can call `onPurchaseRequest`. True only when the SDK is
172
+ * ready and a `storeUrl` prop is set. Compatible with mobile/unavailable
173
+ * hosts that still want a store CTA.
174
+ */
166
175
  canBuyNow: boolean;
176
+ /** Mute active stream audio. No acknowledgement is returned. */
177
+ mute: () => void;
178
+ /** Resume and unmute stream audio. No acknowledgement is returned. */
179
+ unmute: () => void;
167
180
  /** Send the password collected by the host to a protected operation. */
168
181
  submitPassword: (password: string) => void;
169
182
  /**
@@ -268,7 +281,7 @@ interface EmbedTesterProps {
268
281
  enableWindowedLaunch?: boolean;
269
282
  className?: string;
270
283
  }
271
- declare const EmbedTester: (props?: EmbedTesterProps) => react_jsx_runtime.JSX.Element;
284
+ declare const EmbedTester: (props?: EmbedTesterProps) => React$1.JSX.Element;
272
285
 
273
286
  interface BuildUrlParams {
274
287
  operation: string;
@@ -291,8 +304,8 @@ declare const buildEmbedUrl: ({ operation, operationKey, storeUrl, }: BuildUrlPa
291
304
  declare const PLAYRUO_UUID_STORAGE_KEY = "playruo_uuid";
292
305
  /**
293
306
  * Visitor identity the host answers on `playruo_uuid_request`.
294
- * Same rule as PlayruoEmbed `clientFingerprint`: a non-empty value is used as-is
295
- * and is not written to localStorage. Otherwise the SDK-managed UUID is used.
307
+ * Same rule as PlayruoEmbed `clientFingerprint`: a non-empty trimmed value is
308
+ * used and is not written to localStorage. Otherwise the SDK-managed UUID is used.
296
309
  */
297
310
  declare const resolveVisitorUuid: (clientFingerprint?: string) => string;
298
311
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { FC, ReactNode } from 'react';
2
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import React$1, { FC, ReactNode } from 'react';
3
2
 
4
3
  /**
5
4
  * iframe `allow` feature policy delegated to the Playruo player.
@@ -28,7 +27,13 @@ interface DemoCompletedPayload {
28
27
  type PlayruoEventPayload = Record<string, unknown> & {
29
28
  action?: string;
30
29
  category?: string;
30
+ /**
31
+ * @deprecated The webapp puts the event identifier on `name`. Nothing it
32
+ * posts carries `event`, so a host switching on it never matches. Kept so
33
+ * older hosts still compile.
34
+ */
31
35
  event?: string;
36
+ /** Event identifier, snake_case (`auth_ok`, `streaming`, `vmnok`). */
32
37
  name?: string;
33
38
  };
34
39
 
@@ -162,8 +167,16 @@ interface PlayruoEmbedActions {
162
167
  buyNow: () => void;
163
168
  /** Whether try now is currently available */
164
169
  canTryNow: boolean;
165
- /** Whether buy now is currently available */
170
+ /**
171
+ * Whether buy now can call `onPurchaseRequest`. True only when the SDK is
172
+ * ready and a `storeUrl` prop is set. Compatible with mobile/unavailable
173
+ * hosts that still want a store CTA.
174
+ */
166
175
  canBuyNow: boolean;
176
+ /** Mute active stream audio. No acknowledgement is returned. */
177
+ mute: () => void;
178
+ /** Resume and unmute stream audio. No acknowledgement is returned. */
179
+ unmute: () => void;
167
180
  /** Send the password collected by the host to a protected operation. */
168
181
  submitPassword: (password: string) => void;
169
182
  /**
@@ -268,7 +281,7 @@ interface EmbedTesterProps {
268
281
  enableWindowedLaunch?: boolean;
269
282
  className?: string;
270
283
  }
271
- declare const EmbedTester: (props?: EmbedTesterProps) => react_jsx_runtime.JSX.Element;
284
+ declare const EmbedTester: (props?: EmbedTesterProps) => React$1.JSX.Element;
272
285
 
273
286
  interface BuildUrlParams {
274
287
  operation: string;
@@ -291,8 +304,8 @@ declare const buildEmbedUrl: ({ operation, operationKey, storeUrl, }: BuildUrlPa
291
304
  declare const PLAYRUO_UUID_STORAGE_KEY = "playruo_uuid";
292
305
  /**
293
306
  * Visitor identity the host answers on `playruo_uuid_request`.
294
- * Same rule as PlayruoEmbed `clientFingerprint`: a non-empty value is used as-is
295
- * and is not written to localStorage. Otherwise the SDK-managed UUID is used.
307
+ * Same rule as PlayruoEmbed `clientFingerprint`: a non-empty trimmed value is
308
+ * used and is not written to localStorage. Otherwise the SDK-managed UUID is used.
296
309
  */
297
310
  declare const resolveVisitorUuid: (clientFingerprint?: string) => string;
298
311
 
package/dist/index.js CHANGED
@@ -167,6 +167,14 @@ var PlayruoEmbed = ({
167
167
  }, []);
168
168
  const isCompatible = !isMobile && isValidChromium;
169
169
  const isReady = isCompatible ? isIframeLoaded : true;
170
+ useEffect(() => {
171
+ const iframe = iframeRef.current;
172
+ if (!iframe || iframe.getAttribute("src") === src) {
173
+ return;
174
+ }
175
+ iframe.setAttribute("credentialless", "");
176
+ iframe.src = src;
177
+ }, [iframeRef, isCompatible, src]);
170
178
  const currentState = useMemo(() => {
171
179
  if (iframeState) {
172
180
  return iframeState;
@@ -239,7 +247,7 @@ var PlayruoEmbed = ({
239
247
  embedOrigin
240
248
  );
241
249
  } catch {
242
- console.error("[PlayruoEmbed] Failed to send the password action");
250
+ console.error("[PlayruoEmbed] Failed to send iframe action");
243
251
  }
244
252
  },
245
253
  [embedOrigin, iframeRef]
@@ -762,7 +770,9 @@ var PlayruoEmbed = ({
762
770
  tryNow: handleTryNow,
763
771
  buyNow: handleBuyNow,
764
772
  canTryNow,
765
- canBuyNow: Boolean(isReady),
773
+ canBuyNow: Boolean(isReady && storeUrl),
774
+ mute: () => postPasswordAction({ action: "mute" }),
775
+ unmute: () => postPasswordAction({ action: "unmute" }),
766
776
  submitPassword: (password2) => {
767
777
  if (!password2) {
768
778
  return;
@@ -828,10 +838,8 @@ var PlayruoEmbed = ({
828
838
  "iframe",
829
839
  {
830
840
  ref: iframeRef,
831
- src,
832
841
  allow: PLAYRUO_IFRAME_ALLOW,
833
842
  className: "w-full h-[70vh] rounded-lg border",
834
- ...{ credentialless: "true" },
835
843
  sandbox: "allow-same-origin allow-scripts allow-popups allow-forms allow-presentation allow-top-navigation allow-modals allow-pointer-lock",
836
844
  title: "Playruo",
837
845
  referrerPolicy: "strict-origin-when-cross-origin",
@@ -843,8 +851,10 @@ var PlayruoEmbed = ({
843
851
  height: "100%",
844
852
  border: 0
845
853
  },
846
- onLoad: () => {
847
- setIsIframeLoaded(true);
854
+ onLoad: (event) => {
855
+ if (event.currentTarget.getAttribute("src")) {
856
+ setIsIframeLoaded(true);
857
+ }
848
858
  },
849
859
  onError: () => {
850
860
  console.error("[PlayruoEmbed] Iframe failed to load");
@@ -999,7 +1009,7 @@ var EmbedTester = (props = {}) => {
999
1009
  }
1000
1010
  }, [addEvent, enableConsoleLog]);
1001
1011
  const handleEvent = useCallback2((data) => {
1002
- const eventName = typeof data.event === "string" ? data.event : typeof data.name === "string" ? data.name : "unknown";
1012
+ const eventName = typeof data.name === "string" ? data.name : typeof data.event === "string" ? data.event : "unknown";
1003
1013
  addEvent(`Event received: ${eventName}`);
1004
1014
  if (enableConsoleLog) {
1005
1015
  console.log("Embed event:", data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playruo/embed",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "React SDK to embed Playruo with postMessage API.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,15 +35,21 @@
35
35
  "@types/node": "^26.2.0",
36
36
  "@types/react": "^19",
37
37
  "@types/react-dom": "^19",
38
- "@vitest/browser": "^3.2.7",
39
- "@vitest/coverage-v8": "^3.2.4",
38
+ "@vitest/browser": "^5.0.2",
39
+ "@vitest/browser-playwright": "^5.0.2",
40
+ "@vitest/coverage-v8": "^5.0.2",
40
41
  "jsdom": "^26.1.0",
41
- "playwright": "^1.62.1",
42
+ "playwright": "1.62.1",
42
43
  "react": "^19.1.0",
43
44
  "react-dom": "^19.1.0",
44
45
  "tsup": "^8.0.0",
45
46
  "typescript": "^5.4.0",
46
- "vitest": "^3.2.4"
47
+ "vitest": "^5.0.2"
48
+ },
49
+ "overrides": {
50
+ "esbuild": "^0.28.1",
51
+ "picomatch": "^4.0.4",
52
+ "rollup": "^4.59.0"
47
53
  },
48
54
  "scripts": {
49
55
  "build": "tsup src/index.ts --format esm,cjs --dts --clean",
@@ -52,9 +58,11 @@
52
58
  "typecheck": "tsc -p tsconfig.test.json",
53
59
  "check:exports": "attw --pack .",
54
60
  "test": "npm run build && vitest run --coverage",
61
+ "test:smoke": "vitest run tests/smoke",
55
62
  "test:browser": "vitest run --config vitest.browser.config.ts",
56
63
  "test:watch": "npm run build && vitest",
57
64
  "docs:notion:dry-run": "node scripts/sync-notion-docs.mjs",
58
- "docs:notion:publish": "node scripts/sync-notion-docs.mjs --publish"
65
+ "docs:notion:publish": "node scripts/sync-notion-docs.mjs --publish",
66
+ "docs:catalog:check": "node scripts/check-embed-event-catalog.mjs && node scripts/check-embed-error-catalog.mjs"
59
67
  }
60
68
  }