@longstoryshort/vtt-sdk 0.3.0 → 0.4.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.
@@ -1,4 +1,5 @@
1
1
  import { V as VTTAdapter, a as VTTUser, S as SheetEvent, N as NotifyVariant } from '../../types-w2_82sqo.js';
2
+ import * as _owlbear_rodeo_sdk from '@owlbear-rodeo/sdk';
2
3
 
3
4
  /**
4
5
  * Owlbear Rodeo implementation of {@link VTTAdapter}.
@@ -19,7 +20,6 @@ declare class OwlbearAdapter implements VTTAdapter {
19
20
  get isAvailable(): boolean;
20
21
  ready(): Promise<boolean>;
21
22
  private init;
22
- private loadSdk;
23
23
  getSessionId(): string | undefined;
24
24
  getCurrentUser(): VTTUser | undefined;
25
25
  broadcast(event: SheetEvent): void;
@@ -48,4 +48,36 @@ declare const LABEL_METADATA_KEY = "rodeo.lss/label";
48
48
  /** How long a roll label floats over a token before it is removed. */
49
49
  declare const DEFAULT_LABEL_TTL_MS = 4000;
50
50
 
51
- export { BROADCAST_CHANNEL, DEFAULT_LABEL_TTL_MS, LABEL_METADATA_KEY, OwlbearAdapter, syncObrref };
51
+ interface ObrLike {
52
+ onReady(cb: () => void): void;
53
+ }
54
+ /** Promisifies `OBR.onReady` — resolves once the OBR_READY handshake completes. */
55
+ declare function whenObrReady(obr: ObrLike): Promise<void>;
56
+
57
+ type OwlbearSdk = typeof _owlbear_rodeo_sdk;
58
+ /**
59
+ * The window shape expected by the SDK preload contract.
60
+ * Set `__lssObrSdk` at the app entry (before any navigation) so
61
+ * `loadObrSdk` can reuse the already-imported module and avoid missing
62
+ * the one-shot OBR_READY handshake.
63
+ */
64
+ interface ObrPreloadWindow {
65
+ __lssObrSdk?: OwlbearSdk;
66
+ }
67
+ /**
68
+ * Call this at the bridge entry module — before any client-side navigation —
69
+ * to stash the already-imported OBR SDK so `loadObrSdk` can find it.
70
+ */
71
+ declare function preloadObrSdk(sdk: OwlbearSdk): void;
72
+ /**
73
+ * Retrieves the OBR SDK for use inside an OBR extension frame.
74
+ *
75
+ * Prefers the copy stashed by `preloadObrSdk` (imported early enough to catch
76
+ * the one-shot OBR_READY handshake). Falls back to a dynamic import if the
77
+ * stash is absent, with a warning — the dynamic path may miss OBR_READY.
78
+ *
79
+ * Returns `null` when not running in a browser or when the import fails.
80
+ */
81
+ declare function loadObrSdk(): Promise<OwlbearSdk | null>;
82
+
83
+ export { BROADCAST_CHANNEL, DEFAULT_LABEL_TTL_MS, LABEL_METADATA_KEY, type ObrPreloadWindow, OwlbearAdapter, loadObrSdk, preloadObrSdk, syncObrref, whenObrReady };
@@ -44,8 +44,44 @@ function syncObrref() {
44
44
  }
45
45
  }
46
46
 
47
- // src/adapters/owlbear/OwlbearAdapter.ts
47
+ // src/adapters/owlbear/loadObrSdk.ts
48
48
  var DEV2 = process.env["NODE_ENV"] !== "production";
49
+ function preloadObrSdk(sdk) {
50
+ window.__lssObrSdk = sdk;
51
+ }
52
+ async function loadObrSdk() {
53
+ if (typeof window === "undefined") {
54
+ return null;
55
+ }
56
+ const host = window;
57
+ for (let i = 0; i < 10 && !host.__lssObrSdk; i += 1) {
58
+ await new Promise((resolve) => {
59
+ window.setTimeout(resolve, 50);
60
+ });
61
+ }
62
+ if (host.__lssObrSdk) {
63
+ return host.__lssObrSdk;
64
+ }
65
+ if (DEV2) {
66
+ console.warn("[LSS/OBR] no preloaded SDK \u2014 importing now (may miss OBR_READY)");
67
+ }
68
+ try {
69
+ return await import('@owlbear-rodeo/sdk');
70
+ } catch (error) {
71
+ console.error("[LSS/OBR] SDK import failed:", error);
72
+ return null;
73
+ }
74
+ }
75
+
76
+ // src/adapters/owlbear/whenObrReady.ts
77
+ function whenObrReady(obr) {
78
+ return new Promise((resolve) => {
79
+ obr.onReady(resolve);
80
+ });
81
+ }
82
+
83
+ // src/adapters/owlbear/OwlbearAdapter.ts
84
+ var DEV3 = process.env["NODE_ENV"] !== "production";
49
85
  var NOTIFY_VARIANT = {
50
86
  info: "INFO",
51
87
  success: "SUCCESS",
@@ -73,13 +109,13 @@ var OwlbearAdapter = class {
73
109
  return false;
74
110
  }
75
111
  syncObrref();
76
- const sdk = await this.loadSdk();
112
+ const sdk = await loadObrSdk();
77
113
  if (!sdk) {
78
114
  return false;
79
115
  }
80
116
  this.sdk = sdk;
81
117
  this.obr = sdk.default;
82
- if (DEV2) {
118
+ if (DEV3) {
83
119
  console.info(
84
120
  "[LSS/OBR] init \u2014 isAvailable:",
85
121
  this.obr.isAvailable,
@@ -88,18 +124,16 @@ var OwlbearAdapter = class {
88
124
  );
89
125
  }
90
126
  if (!this.obr.isAvailable) {
91
- if (DEV2) {
127
+ if (DEV3) {
92
128
  console.warn("[LSS/OBR] not embedded (origin empty) \u2014 obrref missing at SDK load.");
93
129
  }
94
130
  return false;
95
131
  }
96
- if (DEV2) {
132
+ if (DEV3) {
97
133
  console.info("[LSS/OBR] awaiting onReady (isReady =", this.obr.isReady, ")");
98
134
  }
99
- await new Promise((resolve) => {
100
- this.obr.onReady(resolve);
101
- });
102
- if (DEV2) {
135
+ await whenObrReady(this.obr);
136
+ if (DEV3) {
103
137
  console.info("[LSS/OBR] onReady fired \u2014 fetching player\u2026");
104
138
  }
105
139
  if (this.disposed) {
@@ -112,31 +146,11 @@ var OwlbearAdapter = class {
112
146
  this.obr.player.getRole()
113
147
  ]);
114
148
  this.user = { id, name, role: role === "GM" ? "gm" : "player" };
115
- if (DEV2) {
149
+ if (DEV3) {
116
150
  console.info("[LSS/OBR] ready \u2014 room:", this.sessionId, "user:", this.user);
117
151
  }
118
152
  return true;
119
153
  }
120
- async loadSdk() {
121
- const host = window;
122
- for (let i = 0; i < 10 && !host.__lssObrSdk; i += 1) {
123
- await new Promise((resolve) => {
124
- window.setTimeout(resolve, 50);
125
- });
126
- }
127
- if (host.__lssObrSdk) {
128
- return host.__lssObrSdk;
129
- }
130
- if (DEV2) {
131
- console.warn("[LSS/OBR] no preloaded SDK \u2014 importing now (may miss OBR_READY)");
132
- }
133
- try {
134
- return await import('@owlbear-rodeo/sdk');
135
- } catch (error) {
136
- console.error("[LSS/OBR] SDK import failed:", error);
137
- return null;
138
- }
139
- }
140
154
  getSessionId() {
141
155
  return this.sessionId;
142
156
  }
@@ -168,14 +182,14 @@ var OwlbearAdapter = class {
168
182
  try {
169
183
  const selection = await obr.player.getSelection();
170
184
  if (!selection || selection.length !== 1) {
171
- if (DEV2) {
185
+ if (DEV3) {
172
186
  console.warn("[OwlbearAdapter] label skipped \u2014 selected tokens:", selection?.length ?? 0);
173
187
  }
174
188
  return false;
175
189
  }
176
190
  const [token] = await obr.scene.items.getItems(selection);
177
191
  if (!token) {
178
- if (DEV2) {
192
+ if (DEV3) {
179
193
  console.warn("[OwlbearAdapter] label skipped \u2014 selected item not found in scene");
180
194
  }
181
195
  return false;
@@ -188,7 +202,7 @@ var OwlbearAdapter = class {
188
202
  }, ttlMs);
189
203
  return true;
190
204
  } catch (error) {
191
- if (DEV2) {
205
+ if (DEV3) {
192
206
  console.warn("[OwlbearAdapter] label error:", error);
193
207
  }
194
208
  return false;
@@ -199,4 +213,4 @@ var OwlbearAdapter = class {
199
213
  }
200
214
  };
201
215
 
202
- export { BROADCAST_CHANNEL, DEFAULT_LABEL_TTL_MS, LABEL_METADATA_KEY, OwlbearAdapter, syncObrref };
216
+ export { BROADCAST_CHANNEL, DEFAULT_LABEL_TTL_MS, LABEL_METADATA_KEY, OwlbearAdapter, loadObrSdk, preloadObrSdk, syncObrref, whenObrReady };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,13 @@
1
1
  import { b as SheetSource, V as VTTAdapter, R as RollBridgeOptions, c as SheetClientOptions, d as SheetClient, C as CapabilityManifest, S as SheetEvent, M as MessageHost, D as DiceRollPayload, N as NotifyVariant } from './types-w2_82sqo.js';
2
2
  export { e as CapabilityDescriptor, f as CapabilityOpAddTag, g as CapabilityOpAdjust, h as CapabilityOpName, i as CapabilityOpRemoveTag, j as CapabilityOpRequestRoll, k as CapabilityOpSet, l as CapabilityOpToggle, m as CapabilityOperation, H as HealthChangedPayload, n as MessageTarget, o as RollBridgeMessages, a as VTTUser, p as VTTUserRole } from './types-w2_82sqo.js';
3
3
 
4
+ /**
5
+ * Minimum sandbox tokens required on the sheet iframe.
6
+ * `allow-same-origin` is essential — without it the sheet gets an opaque origin
7
+ * and auth (cookies / localStorage) breaks entirely.
8
+ */
9
+ declare const SHEET_IFRAME_SANDBOX = "allow-same-origin allow-scripts allow-popups allow-popups-to-escape-sandbox allow-forms allow-modals";
10
+
4
11
  /**
5
12
  * The default roll bridge — one opinionated policy, not the full protocol.
6
13
  *
@@ -72,4 +79,4 @@ declare function formatRollMessage(payload: DiceRollPayload): string;
72
79
  /** Maps a roll's crit state onto a toast variant. */
73
80
  declare function rollVariant(payload: DiceRollPayload): NotifyVariant;
74
81
 
75
- export { type BridgeSheetSource, type BridgeSheetSourceOptions, CapabilityManifest, DiceRollPayload, MessageHost, NotifyVariant, RollBridgeOptions, SheetClient, SheetClientOptions, SheetEvent, type SheetFrameRef, SheetSource, VTTAdapter, createBridgeSheetSource, createRollBridge, createSheetClient, formatRollMessage, rollVariant };
82
+ export { type BridgeSheetSource, type BridgeSheetSourceOptions, CapabilityManifest, DiceRollPayload, MessageHost, NotifyVariant, RollBridgeOptions, SHEET_IFRAME_SANDBOX, SheetClient, SheetClientOptions, SheetEvent, type SheetFrameRef, SheetSource, VTTAdapter, createBridgeSheetSource, createRollBridge, createSheetClient, formatRollMessage, rollVariant };
package/dist/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ // src/constants.ts
2
+ var SHEET_IFRAME_SANDBOX = "allow-same-origin allow-scripts allow-popups allow-popups-to-escape-sandbox allow-forms allow-modals";
3
+
1
4
  // src/formatRoll.ts
2
5
  function formatRollMessage(payload) {
3
6
  let crit = "";
@@ -185,4 +188,4 @@ function createBridgeSheetSource(options) {
185
188
  };
186
189
  }
187
190
 
188
- export { createBridgeSheetSource, createRollBridge, createSheetClient, formatRollMessage, rollVariant };
191
+ export { SHEET_IFRAME_SANDBOX, createBridgeSheetSource, createRollBridge, createSheetClient, formatRollMessage, rollVariant };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@longstoryshort/vtt-sdk",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Embed a longstoryshort.app character sheet in any virtual tabletop via iframe and postMessage",
5
5
  "license": "MIT",
6
6
  "type": "module",