@oasiz/sdk 1.5.1 → 1.5.2

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
@@ -298,7 +298,18 @@ quitButton.addEventListener("click", () => {
298
298
  });
299
299
  ```
300
300
 
301
- #### `oasiz.onLeaveGame(callback: () => void): Unsubscribe`
301
+ ### `oasiz.share(options: { text?: string; score?: number; image?: string }): Promise<void>`
302
+
303
+ Ask the host to open the same share flow Oasiz already uses today. Use `text` to customize the share message, `score` to trigger a challenge-style share, and `image` to share an `http(s)` URL or `data:image/...` payload.
304
+
305
+ ```ts
306
+ await oasiz.share({
307
+ text: "I made it to level 9!",
308
+ score: 4200,
309
+ });
310
+ ```
311
+
312
+ ### `oasiz.onLeaveGame(callback: () => void): Unsubscribe`
302
313
 
303
314
  Registers a callback fired when the host initiates closing the game (for example, close button, gesture, or host navigation). Use this for lightweight cleanup.
304
315
 
@@ -375,6 +386,7 @@ All methods are also available as named exports if you prefer not to use the `oa
375
386
  ```ts
376
387
  import {
377
388
  submitScore,
389
+ share,
378
390
  triggerHaptic,
379
391
  loadGameState,
380
392
  saveGameState,
@@ -406,6 +418,7 @@ import type {
406
418
  LogOverlayHandle,
407
419
  LogOverlayLevel,
408
420
  LogOverlayOptions,
421
+ ShareRequest,
409
422
  ShareRoomCodeOptions,
410
423
  Unsubscribe,
411
424
  } from "@oasiz/sdk";
@@ -491,6 +504,7 @@ public class GameManager : MonoBehaviour
491
504
  | `oasiz.onBackButton` | `OasizSDK.OnBackButton` or `SubscribeBackButton(Action)` (reference-counts `__oasizSetBackOverride`) |
492
505
  | `oasiz.onLeaveGame` | `OasizSDK.OnLeaveGame` |
493
506
  | `oasiz.leaveGame()` | `OasizSDK.LeaveGame()` |
507
+ | `oasiz.share(request)` | `OasizSDK.Share(ShareRequest)` |
494
508
  | `oasiz.shareRoomCode` | `OasizSDK.ShareRoomCode(string, ShareRoomCodeOptions)` |
495
509
  | `oasiz.openInviteModal()` | `OasizSDK.OpenInviteModal()` |
496
510
  | `oasiz.gameId` / `roomCode` / ... | `OasizSDK.GameId` / `RoomCode` / `PlayerName` / `PlayerAvatar` |
@@ -498,6 +512,19 @@ public class GameManager : MonoBehaviour
498
512
  | `oasiz.enableLogOverlay` | `OasizSDK.EnableLogOverlay(LogOverlayOptions)` (see note below) |
499
513
  | -- | `OasizSDK.AppendLogOverlay(level, message, stackTrace)` (see note below) |
500
514
 
515
+ ### Share (Unity)
516
+
517
+ HTML5 **`oasiz.share`** returns a **Promise** you can `await`. Unity **`OasizSDK.Share(ShareRequest)`** returns **`void`**: C# validation throws **`ArgumentException`** with the same rules as TypeScript (at least one of text, score, or image; non-negative integer score; `http(s)` or `data:image/...;base64,...` image). The call forwards JSON to **`window.__oasizShareRequest`**. If the host promise rejects, the **WebGL `.jslib` logs the error** to the browser console.
518
+
519
+ ```csharp
520
+ OasizSDK.Share(new ShareRequest
521
+ {
522
+ Text = "Beat this run!",
523
+ Score = 1200,
524
+ Image = "https://example.com/card.png",
525
+ });
526
+ ```
527
+
501
528
  ### Types
502
529
 
503
530
  ```csharp
@@ -508,6 +535,14 @@ public enum HapticType { Light, Medium, Heavy, Success, Error }
508
535
  public struct ScoreAnchor { public int raw; public int normalized; }
509
536
  public struct ScoreConfig { public ScoreAnchor[] anchors; }
510
537
 
538
+ // Host share sheet (text / score / image URL or data URL)
539
+ public class ShareRequest
540
+ {
541
+ public string Text { get; set; }
542
+ public int? Score { get; set; }
543
+ public string Image { get; set; }
544
+ }
545
+
511
546
  // Multiplayer invite options
512
547
  public class ShareRoomCodeOptions { public bool InviteOverride { get; set; } }
513
548
 
package/dist/index.cjs CHANGED
@@ -37,6 +37,7 @@ __export(index_exports, {
37
37
  openInviteModal: () => openInviteModal,
38
38
  saveGameState: () => saveGameState,
39
39
  setLeaderboardVisible: () => setLeaderboardVisible,
40
+ share: () => share,
40
41
  shareRoomCode: () => shareRoomCode,
41
42
  submitScore: () => submitScore,
42
43
  triggerHaptic: () => triggerHaptic
@@ -1044,7 +1045,7 @@ function submitScore(score) {
1044
1045
  warnMissingBridge("submitScore");
1045
1046
  }
1046
1047
 
1047
- // src/state.ts
1048
+ // src/share.ts
1048
1049
  function isDevelopment4() {
1049
1050
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1050
1051
  return nodeEnv !== "production";
@@ -1055,6 +1056,69 @@ function getBridgeWindow4() {
1055
1056
  }
1056
1057
  return window;
1057
1058
  }
1059
+ function warnMissingBridge2(methodName) {
1060
+ if (isDevelopment4()) {
1061
+ console.warn(
1062
+ "[oasiz/sdk] " + methodName + " share bridge is unavailable. This is expected in local development."
1063
+ );
1064
+ }
1065
+ }
1066
+ function isValidImageReference(image) {
1067
+ if (/^data:image\/[a-zA-Z0-9.+-]+;base64,/.test(image)) {
1068
+ return true;
1069
+ }
1070
+ try {
1071
+ const parsed = new URL(image);
1072
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
1073
+ } catch {
1074
+ return false;
1075
+ }
1076
+ }
1077
+ function validateRequest(options) {
1078
+ const text = typeof options.text === "string" ? options.text.trim() : "";
1079
+ const hasText = text.length > 0;
1080
+ const hasScore = options.score !== void 0;
1081
+ const hasImage = typeof options.image === "string" && options.image.length > 0;
1082
+ if (!hasText && !hasScore && !hasImage) {
1083
+ throw new Error("Share request requires text, score, or image.");
1084
+ }
1085
+ if (hasScore) {
1086
+ if (typeof options.score !== "number" || !Number.isInteger(options.score) || options.score < 0) {
1087
+ throw new Error("Share score must be a non-negative integer.");
1088
+ }
1089
+ }
1090
+ if (hasImage && !isValidImageReference(options.image)) {
1091
+ throw new Error(
1092
+ "Share image must be an http(s) URL or a data:image/... base64 string."
1093
+ );
1094
+ }
1095
+ return {
1096
+ ...hasText ? { text } : {},
1097
+ ...hasScore ? { score: options.score } : {},
1098
+ ...hasImage ? { image: options.image } : {}
1099
+ };
1100
+ }
1101
+ async function share(options) {
1102
+ const request = validateRequest(options);
1103
+ const bridge = getBridgeWindow4();
1104
+ if (typeof bridge?.__oasizShareRequest !== "function") {
1105
+ warnMissingBridge2("__oasizShareRequest");
1106
+ throw new Error("Share bridge unavailable");
1107
+ }
1108
+ await bridge.__oasizShareRequest(request);
1109
+ }
1110
+
1111
+ // src/state.ts
1112
+ function isDevelopment5() {
1113
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1114
+ return nodeEnv !== "production";
1115
+ }
1116
+ function getBridgeWindow5() {
1117
+ if (typeof window === "undefined") {
1118
+ return void 0;
1119
+ }
1120
+ return window;
1121
+ }
1058
1122
  function isPlainObject(value) {
1059
1123
  if (!value || typeof value !== "object" || Array.isArray(value)) {
1060
1124
  return false;
@@ -1062,22 +1126,22 @@ function isPlainObject(value) {
1062
1126
  const proto = Object.getPrototypeOf(value);
1063
1127
  return proto === Object.prototype || proto === null;
1064
1128
  }
1065
- function warnMissingBridge2(methodName) {
1066
- if (isDevelopment4()) {
1129
+ function warnMissingBridge3(methodName) {
1130
+ if (isDevelopment5()) {
1067
1131
  console.warn(
1068
1132
  "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1069
1133
  );
1070
1134
  }
1071
1135
  }
1072
1136
  function loadGameState() {
1073
- const bridge = getBridgeWindow4();
1137
+ const bridge = getBridgeWindow5();
1074
1138
  if (typeof bridge?.loadGameState !== "function") {
1075
- warnMissingBridge2("loadGameState");
1139
+ warnMissingBridge3("loadGameState");
1076
1140
  return {};
1077
1141
  }
1078
1142
  const state = bridge.loadGameState();
1079
1143
  if (!isPlainObject(state)) {
1080
- if (isDevelopment4()) {
1144
+ if (isDevelopment5()) {
1081
1145
  console.warn(
1082
1146
  "[oasiz/sdk] loadGameState returned invalid data. Falling back to empty object."
1083
1147
  );
@@ -1088,35 +1152,35 @@ function loadGameState() {
1088
1152
  }
1089
1153
  function saveGameState(state) {
1090
1154
  if (!isPlainObject(state)) {
1091
- if (isDevelopment4()) {
1155
+ if (isDevelopment5()) {
1092
1156
  console.warn("[oasiz/sdk] saveGameState expected a plain object:", state);
1093
1157
  }
1094
1158
  return;
1095
1159
  }
1096
- const bridge = getBridgeWindow4();
1160
+ const bridge = getBridgeWindow5();
1097
1161
  if (typeof bridge?.saveGameState === "function") {
1098
1162
  bridge.saveGameState(state);
1099
1163
  return;
1100
1164
  }
1101
- warnMissingBridge2("saveGameState");
1165
+ warnMissingBridge3("saveGameState");
1102
1166
  }
1103
1167
  function flushGameState() {
1104
- const bridge = getBridgeWindow4();
1168
+ const bridge = getBridgeWindow5();
1105
1169
  if (typeof bridge?.flushGameState === "function") {
1106
1170
  bridge.flushGameState();
1107
1171
  return;
1108
1172
  }
1109
- warnMissingBridge2("flushGameState");
1173
+ warnMissingBridge3("flushGameState");
1110
1174
  }
1111
1175
 
1112
1176
  // src/lifecycle.ts
1113
- function isDevelopment5() {
1177
+ function isDevelopment6() {
1114
1178
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1115
1179
  return nodeEnv !== "production";
1116
1180
  }
1117
1181
  function addLifecycleListener(eventName, callback) {
1118
1182
  if (typeof window === "undefined") {
1119
- if (isDevelopment5()) {
1183
+ if (isDevelopment6()) {
1120
1184
  console.warn(
1121
1185
  "[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
1122
1186
  );
@@ -1136,18 +1200,18 @@ function onResume(callback) {
1136
1200
  }
1137
1201
 
1138
1202
  // src/layout.ts
1139
- function isDevelopment6() {
1203
+ function isDevelopment7() {
1140
1204
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1141
1205
  return nodeEnv !== "production";
1142
1206
  }
1143
- function getBridgeWindow5() {
1207
+ function getBridgeWindow6() {
1144
1208
  if (typeof window === "undefined") {
1145
1209
  return void 0;
1146
1210
  }
1147
1211
  return window;
1148
1212
  }
1149
- function warnMissingBridge3(methodName) {
1150
- if (isDevelopment6()) {
1213
+ function warnMissingBridge4(methodName) {
1214
+ if (isDevelopment7()) {
1151
1215
  console.warn(
1152
1216
  "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1153
1217
  );
@@ -1160,7 +1224,7 @@ function normalizeSafeAreaTop(value) {
1160
1224
  return Math.max(0, value);
1161
1225
  }
1162
1226
  function getSafeAreaTop() {
1163
- const bridge = getBridgeWindow5();
1227
+ const bridge = getBridgeWindow6();
1164
1228
  if (!bridge) {
1165
1229
  return 0;
1166
1230
  }
@@ -1170,12 +1234,12 @@ function getSafeAreaTop() {
1170
1234
  if (typeof bridge.__OASIZ_SAFE_AREA_TOP__ !== "undefined") {
1171
1235
  return normalizeSafeAreaTop(bridge.__OASIZ_SAFE_AREA_TOP__);
1172
1236
  }
1173
- warnMissingBridge3("getSafeAreaTop");
1237
+ warnMissingBridge4("getSafeAreaTop");
1174
1238
  return 0;
1175
1239
  }
1176
1240
  function setLeaderboardVisible(visible) {
1177
1241
  if (typeof visible !== "boolean") {
1178
- if (isDevelopment6()) {
1242
+ if (isDevelopment7()) {
1179
1243
  console.warn(
1180
1244
  "[oasiz/sdk] setLeaderboardVisible expected a boolean:",
1181
1245
  visible
@@ -1183,28 +1247,28 @@ function setLeaderboardVisible(visible) {
1183
1247
  }
1184
1248
  return;
1185
1249
  }
1186
- const bridge = getBridgeWindow5();
1250
+ const bridge = getBridgeWindow6();
1187
1251
  if (typeof bridge?.__oasizSetLeaderboardVisible === "function") {
1188
1252
  bridge.__oasizSetLeaderboardVisible(visible);
1189
1253
  return;
1190
1254
  }
1191
- warnMissingBridge3("__oasizSetLeaderboardVisible");
1255
+ warnMissingBridge4("__oasizSetLeaderboardVisible");
1192
1256
  }
1193
1257
 
1194
1258
  // src/navigation.ts
1195
1259
  var activeBackListeners = 0;
1196
- function isDevelopment7() {
1260
+ function isDevelopment8() {
1197
1261
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1198
1262
  return nodeEnv !== "production";
1199
1263
  }
1200
- function getBridgeWindow6() {
1264
+ function getBridgeWindow7() {
1201
1265
  if (typeof window === "undefined") {
1202
1266
  return void 0;
1203
1267
  }
1204
1268
  return window;
1205
1269
  }
1206
- function warnMissingBridge4(methodName) {
1207
- if (isDevelopment7()) {
1270
+ function warnMissingBridge5(methodName) {
1271
+ if (isDevelopment8()) {
1208
1272
  console.warn(
1209
1273
  "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1210
1274
  );
@@ -1220,7 +1284,7 @@ function normalizeNavigationError(error) {
1220
1284
  }
1221
1285
  function addNavigationListener(eventName, callback) {
1222
1286
  if (typeof window === "undefined") {
1223
- if (isDevelopment7()) {
1287
+ if (isDevelopment8()) {
1224
1288
  console.warn(
1225
1289
  "[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
1226
1290
  );
@@ -1241,24 +1305,24 @@ function onBackButton(callback) {
1241
1305
  throw normalizeNavigationError(error);
1242
1306
  }
1243
1307
  });
1244
- const bridge = getBridgeWindow6();
1308
+ const bridge = getBridgeWindow7();
1245
1309
  activeBackListeners += 1;
1246
1310
  if (activeBackListeners === 1) {
1247
1311
  if (typeof bridge?.__oasizSetBackOverride === "function") {
1248
1312
  bridge.__oasizSetBackOverride(true);
1249
1313
  } else {
1250
- warnMissingBridge4("__oasizSetBackOverride");
1314
+ warnMissingBridge5("__oasizSetBackOverride");
1251
1315
  }
1252
1316
  }
1253
1317
  return () => {
1254
1318
  off();
1255
1319
  activeBackListeners = Math.max(0, activeBackListeners - 1);
1256
1320
  if (activeBackListeners === 0) {
1257
- const currentBridge = getBridgeWindow6();
1321
+ const currentBridge = getBridgeWindow7();
1258
1322
  if (typeof currentBridge?.__oasizSetBackOverride === "function") {
1259
1323
  currentBridge.__oasizSetBackOverride(false);
1260
1324
  } else {
1261
- warnMissingBridge4("__oasizSetBackOverride");
1325
+ warnMissingBridge5("__oasizSetBackOverride");
1262
1326
  }
1263
1327
  }
1264
1328
  };
@@ -1267,17 +1331,18 @@ function onLeaveGame(callback) {
1267
1331
  return addNavigationListener("oasiz:leave", callback);
1268
1332
  }
1269
1333
  function leaveGame() {
1270
- const bridge = getBridgeWindow6();
1334
+ const bridge = getBridgeWindow7();
1271
1335
  if (typeof bridge?.__oasizLeaveGame === "function") {
1272
1336
  bridge.__oasizLeaveGame();
1273
1337
  return;
1274
1338
  }
1275
- warnMissingBridge4("__oasizLeaveGame");
1339
+ warnMissingBridge5("__oasizLeaveGame");
1276
1340
  }
1277
1341
 
1278
1342
  // src/index.ts
1279
1343
  var oasiz = {
1280
1344
  submitScore,
1345
+ share,
1281
1346
  triggerHaptic,
1282
1347
  enableLogOverlay,
1283
1348
  loadGameState,
@@ -1327,6 +1392,7 @@ var oasiz = {
1327
1392
  openInviteModal,
1328
1393
  saveGameState,
1329
1394
  setLeaderboardVisible,
1395
+ share,
1330
1396
  shareRoomCode,
1331
1397
  submitScore,
1332
1398
  triggerHaptic
package/dist/index.d.cts CHANGED
@@ -20,6 +20,11 @@ interface LogOverlayHandle {
20
20
  show: () => void;
21
21
  }
22
22
  type GameState = Record<string, unknown>;
23
+ interface ShareRequest {
24
+ image?: string;
25
+ score?: number;
26
+ text?: string;
27
+ }
23
28
 
24
29
  declare function triggerHaptic(type: HapticType): void;
25
30
 
@@ -47,6 +52,8 @@ declare function getPlayerAvatar(): string | undefined;
47
52
 
48
53
  declare function submitScore(score: number): void;
49
54
 
55
+ declare function share(options: ShareRequest): Promise<void>;
56
+
50
57
  declare function loadGameState(): GameState;
51
58
  declare function saveGameState(state: GameState): void;
52
59
  declare function flushGameState(): void;
@@ -64,6 +71,7 @@ declare function leaveGame(): void;
64
71
 
65
72
  declare const oasiz: {
66
73
  submitScore: typeof submitScore;
74
+ share: typeof share;
67
75
  triggerHaptic: typeof triggerHaptic;
68
76
  enableLogOverlay: typeof enableLogOverlay;
69
77
  loadGameState: typeof loadGameState;
@@ -85,4 +93,4 @@ declare const oasiz: {
85
93
  readonly safeAreaTop: number;
86
94
  };
87
95
 
88
- export { type GameState, type HapticType, type LogOverlayEntry, type LogOverlayHandle, type LogOverlayLevel, type LogOverlayOptions, type ShareRoomCodeOptions, type Unsubscribe, enableLogOverlay, flushGameState, getGameId, getPlayerAvatar, getPlayerName, getRoomCode, getSafeAreaTop, leaveGame, loadGameState, oasiz, onBackButton, onLeaveGame, onPause, onResume, openInviteModal, saveGameState, setLeaderboardVisible, shareRoomCode, submitScore, triggerHaptic };
96
+ export { type GameState, type HapticType, type LogOverlayEntry, type LogOverlayHandle, type LogOverlayLevel, type LogOverlayOptions, type ShareRequest, type ShareRoomCodeOptions, type Unsubscribe, enableLogOverlay, flushGameState, getGameId, getPlayerAvatar, getPlayerName, getRoomCode, getSafeAreaTop, leaveGame, loadGameState, oasiz, onBackButton, onLeaveGame, onPause, onResume, openInviteModal, saveGameState, setLeaderboardVisible, share, shareRoomCode, submitScore, triggerHaptic };
package/dist/index.d.ts CHANGED
@@ -20,6 +20,11 @@ interface LogOverlayHandle {
20
20
  show: () => void;
21
21
  }
22
22
  type GameState = Record<string, unknown>;
23
+ interface ShareRequest {
24
+ image?: string;
25
+ score?: number;
26
+ text?: string;
27
+ }
23
28
 
24
29
  declare function triggerHaptic(type: HapticType): void;
25
30
 
@@ -47,6 +52,8 @@ declare function getPlayerAvatar(): string | undefined;
47
52
 
48
53
  declare function submitScore(score: number): void;
49
54
 
55
+ declare function share(options: ShareRequest): Promise<void>;
56
+
50
57
  declare function loadGameState(): GameState;
51
58
  declare function saveGameState(state: GameState): void;
52
59
  declare function flushGameState(): void;
@@ -64,6 +71,7 @@ declare function leaveGame(): void;
64
71
 
65
72
  declare const oasiz: {
66
73
  submitScore: typeof submitScore;
74
+ share: typeof share;
67
75
  triggerHaptic: typeof triggerHaptic;
68
76
  enableLogOverlay: typeof enableLogOverlay;
69
77
  loadGameState: typeof loadGameState;
@@ -85,4 +93,4 @@ declare const oasiz: {
85
93
  readonly safeAreaTop: number;
86
94
  };
87
95
 
88
- export { type GameState, type HapticType, type LogOverlayEntry, type LogOverlayHandle, type LogOverlayLevel, type LogOverlayOptions, type ShareRoomCodeOptions, type Unsubscribe, enableLogOverlay, flushGameState, getGameId, getPlayerAvatar, getPlayerName, getRoomCode, getSafeAreaTop, leaveGame, loadGameState, oasiz, onBackButton, onLeaveGame, onPause, onResume, openInviteModal, saveGameState, setLeaderboardVisible, shareRoomCode, submitScore, triggerHaptic };
96
+ export { type GameState, type HapticType, type LogOverlayEntry, type LogOverlayHandle, type LogOverlayLevel, type LogOverlayOptions, type ShareRequest, type ShareRoomCodeOptions, type Unsubscribe, enableLogOverlay, flushGameState, getGameId, getPlayerAvatar, getPlayerName, getRoomCode, getSafeAreaTop, leaveGame, loadGameState, oasiz, onBackButton, onLeaveGame, onPause, onResume, openInviteModal, saveGameState, setLeaderboardVisible, share, shareRoomCode, submitScore, triggerHaptic };
package/dist/index.js CHANGED
@@ -999,7 +999,7 @@ function submitScore(score) {
999
999
  warnMissingBridge("submitScore");
1000
1000
  }
1001
1001
 
1002
- // src/state.ts
1002
+ // src/share.ts
1003
1003
  function isDevelopment4() {
1004
1004
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1005
1005
  return nodeEnv !== "production";
@@ -1010,6 +1010,69 @@ function getBridgeWindow4() {
1010
1010
  }
1011
1011
  return window;
1012
1012
  }
1013
+ function warnMissingBridge2(methodName) {
1014
+ if (isDevelopment4()) {
1015
+ console.warn(
1016
+ "[oasiz/sdk] " + methodName + " share bridge is unavailable. This is expected in local development."
1017
+ );
1018
+ }
1019
+ }
1020
+ function isValidImageReference(image) {
1021
+ if (/^data:image\/[a-zA-Z0-9.+-]+;base64,/.test(image)) {
1022
+ return true;
1023
+ }
1024
+ try {
1025
+ const parsed = new URL(image);
1026
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
1027
+ } catch {
1028
+ return false;
1029
+ }
1030
+ }
1031
+ function validateRequest(options) {
1032
+ const text = typeof options.text === "string" ? options.text.trim() : "";
1033
+ const hasText = text.length > 0;
1034
+ const hasScore = options.score !== void 0;
1035
+ const hasImage = typeof options.image === "string" && options.image.length > 0;
1036
+ if (!hasText && !hasScore && !hasImage) {
1037
+ throw new Error("Share request requires text, score, or image.");
1038
+ }
1039
+ if (hasScore) {
1040
+ if (typeof options.score !== "number" || !Number.isInteger(options.score) || options.score < 0) {
1041
+ throw new Error("Share score must be a non-negative integer.");
1042
+ }
1043
+ }
1044
+ if (hasImage && !isValidImageReference(options.image)) {
1045
+ throw new Error(
1046
+ "Share image must be an http(s) URL or a data:image/... base64 string."
1047
+ );
1048
+ }
1049
+ return {
1050
+ ...hasText ? { text } : {},
1051
+ ...hasScore ? { score: options.score } : {},
1052
+ ...hasImage ? { image: options.image } : {}
1053
+ };
1054
+ }
1055
+ async function share(options) {
1056
+ const request = validateRequest(options);
1057
+ const bridge = getBridgeWindow4();
1058
+ if (typeof bridge?.__oasizShareRequest !== "function") {
1059
+ warnMissingBridge2("__oasizShareRequest");
1060
+ throw new Error("Share bridge unavailable");
1061
+ }
1062
+ await bridge.__oasizShareRequest(request);
1063
+ }
1064
+
1065
+ // src/state.ts
1066
+ function isDevelopment5() {
1067
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1068
+ return nodeEnv !== "production";
1069
+ }
1070
+ function getBridgeWindow5() {
1071
+ if (typeof window === "undefined") {
1072
+ return void 0;
1073
+ }
1074
+ return window;
1075
+ }
1013
1076
  function isPlainObject(value) {
1014
1077
  if (!value || typeof value !== "object" || Array.isArray(value)) {
1015
1078
  return false;
@@ -1017,22 +1080,22 @@ function isPlainObject(value) {
1017
1080
  const proto = Object.getPrototypeOf(value);
1018
1081
  return proto === Object.prototype || proto === null;
1019
1082
  }
1020
- function warnMissingBridge2(methodName) {
1021
- if (isDevelopment4()) {
1083
+ function warnMissingBridge3(methodName) {
1084
+ if (isDevelopment5()) {
1022
1085
  console.warn(
1023
1086
  "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1024
1087
  );
1025
1088
  }
1026
1089
  }
1027
1090
  function loadGameState() {
1028
- const bridge = getBridgeWindow4();
1091
+ const bridge = getBridgeWindow5();
1029
1092
  if (typeof bridge?.loadGameState !== "function") {
1030
- warnMissingBridge2("loadGameState");
1093
+ warnMissingBridge3("loadGameState");
1031
1094
  return {};
1032
1095
  }
1033
1096
  const state = bridge.loadGameState();
1034
1097
  if (!isPlainObject(state)) {
1035
- if (isDevelopment4()) {
1098
+ if (isDevelopment5()) {
1036
1099
  console.warn(
1037
1100
  "[oasiz/sdk] loadGameState returned invalid data. Falling back to empty object."
1038
1101
  );
@@ -1043,35 +1106,35 @@ function loadGameState() {
1043
1106
  }
1044
1107
  function saveGameState(state) {
1045
1108
  if (!isPlainObject(state)) {
1046
- if (isDevelopment4()) {
1109
+ if (isDevelopment5()) {
1047
1110
  console.warn("[oasiz/sdk] saveGameState expected a plain object:", state);
1048
1111
  }
1049
1112
  return;
1050
1113
  }
1051
- const bridge = getBridgeWindow4();
1114
+ const bridge = getBridgeWindow5();
1052
1115
  if (typeof bridge?.saveGameState === "function") {
1053
1116
  bridge.saveGameState(state);
1054
1117
  return;
1055
1118
  }
1056
- warnMissingBridge2("saveGameState");
1119
+ warnMissingBridge3("saveGameState");
1057
1120
  }
1058
1121
  function flushGameState() {
1059
- const bridge = getBridgeWindow4();
1122
+ const bridge = getBridgeWindow5();
1060
1123
  if (typeof bridge?.flushGameState === "function") {
1061
1124
  bridge.flushGameState();
1062
1125
  return;
1063
1126
  }
1064
- warnMissingBridge2("flushGameState");
1127
+ warnMissingBridge3("flushGameState");
1065
1128
  }
1066
1129
 
1067
1130
  // src/lifecycle.ts
1068
- function isDevelopment5() {
1131
+ function isDevelopment6() {
1069
1132
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1070
1133
  return nodeEnv !== "production";
1071
1134
  }
1072
1135
  function addLifecycleListener(eventName, callback) {
1073
1136
  if (typeof window === "undefined") {
1074
- if (isDevelopment5()) {
1137
+ if (isDevelopment6()) {
1075
1138
  console.warn(
1076
1139
  "[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
1077
1140
  );
@@ -1091,18 +1154,18 @@ function onResume(callback) {
1091
1154
  }
1092
1155
 
1093
1156
  // src/layout.ts
1094
- function isDevelopment6() {
1157
+ function isDevelopment7() {
1095
1158
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1096
1159
  return nodeEnv !== "production";
1097
1160
  }
1098
- function getBridgeWindow5() {
1161
+ function getBridgeWindow6() {
1099
1162
  if (typeof window === "undefined") {
1100
1163
  return void 0;
1101
1164
  }
1102
1165
  return window;
1103
1166
  }
1104
- function warnMissingBridge3(methodName) {
1105
- if (isDevelopment6()) {
1167
+ function warnMissingBridge4(methodName) {
1168
+ if (isDevelopment7()) {
1106
1169
  console.warn(
1107
1170
  "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1108
1171
  );
@@ -1115,7 +1178,7 @@ function normalizeSafeAreaTop(value) {
1115
1178
  return Math.max(0, value);
1116
1179
  }
1117
1180
  function getSafeAreaTop() {
1118
- const bridge = getBridgeWindow5();
1181
+ const bridge = getBridgeWindow6();
1119
1182
  if (!bridge) {
1120
1183
  return 0;
1121
1184
  }
@@ -1125,12 +1188,12 @@ function getSafeAreaTop() {
1125
1188
  if (typeof bridge.__OASIZ_SAFE_AREA_TOP__ !== "undefined") {
1126
1189
  return normalizeSafeAreaTop(bridge.__OASIZ_SAFE_AREA_TOP__);
1127
1190
  }
1128
- warnMissingBridge3("getSafeAreaTop");
1191
+ warnMissingBridge4("getSafeAreaTop");
1129
1192
  return 0;
1130
1193
  }
1131
1194
  function setLeaderboardVisible(visible) {
1132
1195
  if (typeof visible !== "boolean") {
1133
- if (isDevelopment6()) {
1196
+ if (isDevelopment7()) {
1134
1197
  console.warn(
1135
1198
  "[oasiz/sdk] setLeaderboardVisible expected a boolean:",
1136
1199
  visible
@@ -1138,28 +1201,28 @@ function setLeaderboardVisible(visible) {
1138
1201
  }
1139
1202
  return;
1140
1203
  }
1141
- const bridge = getBridgeWindow5();
1204
+ const bridge = getBridgeWindow6();
1142
1205
  if (typeof bridge?.__oasizSetLeaderboardVisible === "function") {
1143
1206
  bridge.__oasizSetLeaderboardVisible(visible);
1144
1207
  return;
1145
1208
  }
1146
- warnMissingBridge3("__oasizSetLeaderboardVisible");
1209
+ warnMissingBridge4("__oasizSetLeaderboardVisible");
1147
1210
  }
1148
1211
 
1149
1212
  // src/navigation.ts
1150
1213
  var activeBackListeners = 0;
1151
- function isDevelopment7() {
1214
+ function isDevelopment8() {
1152
1215
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1153
1216
  return nodeEnv !== "production";
1154
1217
  }
1155
- function getBridgeWindow6() {
1218
+ function getBridgeWindow7() {
1156
1219
  if (typeof window === "undefined") {
1157
1220
  return void 0;
1158
1221
  }
1159
1222
  return window;
1160
1223
  }
1161
- function warnMissingBridge4(methodName) {
1162
- if (isDevelopment7()) {
1224
+ function warnMissingBridge5(methodName) {
1225
+ if (isDevelopment8()) {
1163
1226
  console.warn(
1164
1227
  "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1165
1228
  );
@@ -1175,7 +1238,7 @@ function normalizeNavigationError(error) {
1175
1238
  }
1176
1239
  function addNavigationListener(eventName, callback) {
1177
1240
  if (typeof window === "undefined") {
1178
- if (isDevelopment7()) {
1241
+ if (isDevelopment8()) {
1179
1242
  console.warn(
1180
1243
  "[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
1181
1244
  );
@@ -1196,24 +1259,24 @@ function onBackButton(callback) {
1196
1259
  throw normalizeNavigationError(error);
1197
1260
  }
1198
1261
  });
1199
- const bridge = getBridgeWindow6();
1262
+ const bridge = getBridgeWindow7();
1200
1263
  activeBackListeners += 1;
1201
1264
  if (activeBackListeners === 1) {
1202
1265
  if (typeof bridge?.__oasizSetBackOverride === "function") {
1203
1266
  bridge.__oasizSetBackOverride(true);
1204
1267
  } else {
1205
- warnMissingBridge4("__oasizSetBackOverride");
1268
+ warnMissingBridge5("__oasizSetBackOverride");
1206
1269
  }
1207
1270
  }
1208
1271
  return () => {
1209
1272
  off();
1210
1273
  activeBackListeners = Math.max(0, activeBackListeners - 1);
1211
1274
  if (activeBackListeners === 0) {
1212
- const currentBridge = getBridgeWindow6();
1275
+ const currentBridge = getBridgeWindow7();
1213
1276
  if (typeof currentBridge?.__oasizSetBackOverride === "function") {
1214
1277
  currentBridge.__oasizSetBackOverride(false);
1215
1278
  } else {
1216
- warnMissingBridge4("__oasizSetBackOverride");
1279
+ warnMissingBridge5("__oasizSetBackOverride");
1217
1280
  }
1218
1281
  }
1219
1282
  };
@@ -1222,17 +1285,18 @@ function onLeaveGame(callback) {
1222
1285
  return addNavigationListener("oasiz:leave", callback);
1223
1286
  }
1224
1287
  function leaveGame() {
1225
- const bridge = getBridgeWindow6();
1288
+ const bridge = getBridgeWindow7();
1226
1289
  if (typeof bridge?.__oasizLeaveGame === "function") {
1227
1290
  bridge.__oasizLeaveGame();
1228
1291
  return;
1229
1292
  }
1230
- warnMissingBridge4("__oasizLeaveGame");
1293
+ warnMissingBridge5("__oasizLeaveGame");
1231
1294
  }
1232
1295
 
1233
1296
  // src/index.ts
1234
1297
  var oasiz = {
1235
1298
  submitScore,
1299
+ share,
1236
1300
  triggerHaptic,
1237
1301
  enableLogOverlay,
1238
1302
  loadGameState,
@@ -1281,6 +1345,7 @@ export {
1281
1345
  openInviteModal,
1282
1346
  saveGameState,
1283
1347
  setLeaderboardVisible,
1348
+ share,
1284
1349
  shareRoomCode,
1285
1350
  submitScore,
1286
1351
  triggerHaptic
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oasiz/sdk",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "Typed SDK for Oasiz game platform bridge APIs.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",