@smoregg/sdk 0.5.0 → 0.6.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/README.md +199 -0
- package/dist/cjs/controller.cjs +379 -0
- package/dist/cjs/controller.cjs.map +1 -0
- package/dist/cjs/index.cjs +8 -4
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/screen.cjs +526 -0
- package/dist/cjs/screen.cjs.map +1 -0
- package/dist/cjs/testing.cjs +257 -0
- package/dist/cjs/testing.cjs.map +1 -0
- package/dist/cjs/transport/protocol.cjs.map +1 -1
- package/dist/esm/controller.js +376 -0
- package/dist/esm/controller.js.map +1 -0
- package/dist/esm/index.js +3 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/screen.js +523 -0
- package/dist/esm/screen.js.map +1 -0
- package/dist/esm/testing.js +254 -0
- package/dist/esm/testing.js.map +1 -0
- package/dist/esm/transport/protocol.js.map +1 -1
- package/dist/types/controller.d.ts +78 -0
- package/dist/types/controller.d.ts.map +1 -0
- package/dist/types/index.d.ts +17 -18
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/screen.d.ts +79 -0
- package/dist/types/screen.d.ts.map +1 -0
- package/dist/types/testing.d.ts +61 -0
- package/dist/types/testing.d.ts.map +1 -0
- package/dist/types/transport/protocol.d.ts +1 -4
- package/dist/types/transport/protocol.d.ts.map +1 -1
- package/dist/types/types.d.ts +869 -4
- package/dist/types/types.d.ts.map +1 -1
- package/dist/umd/smore-sdk-vanilla.umd.js +956 -331
- package/dist/umd/smore-sdk-vanilla.umd.js.map +1 -1
- package/dist/umd/smore-sdk-vanilla.umd.min.js +1 -1
- package/dist/umd/smore-sdk-vanilla.umd.min.js.map +1 -1
- package/dist/umd/smore-sdk.umd.js +956 -331
- package/dist/umd/smore-sdk.umd.js.map +1 -1
- package/dist/umd/smore-sdk.umd.min.js +1 -1
- package/dist/umd/smore-sdk.umd.min.js.map +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# @smoregg/sdk
|
|
2
|
+
|
|
3
|
+
S'MORE Game SDK - Build party games with React for the S'MORE platform.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @smoregg/sdk
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @smoregg/sdk
|
|
11
|
+
# or
|
|
12
|
+
yarn add @smoregg/sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### Screen Game (TV/Display)
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { SmoreScreen } from '@smoregg/sdk';
|
|
21
|
+
|
|
22
|
+
function MyGame() {
|
|
23
|
+
const screen = new SmoreScreen({
|
|
24
|
+
gameId: 'my-game',
|
|
25
|
+
listeners: {
|
|
26
|
+
tap: (playerIndex, data) => {
|
|
27
|
+
console.log(`Player ${playerIndex} tapped!`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return <div>Game UI</div>;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Controller App (Mobile)
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { SmoreController } from '@smoregg/sdk';
|
|
40
|
+
|
|
41
|
+
function MyController() {
|
|
42
|
+
const controller = new SmoreController({
|
|
43
|
+
gameId: 'my-game',
|
|
44
|
+
listeners: {
|
|
45
|
+
'state-update': (state) => {
|
|
46
|
+
console.log('Game state:', state);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<button onClick={() => controller.send('tap', {})}>
|
|
53
|
+
TAP
|
|
54
|
+
</button>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Features
|
|
60
|
+
|
|
61
|
+
- **Screen/Controller Communication**: Simple event-based messaging
|
|
62
|
+
- **React Hooks**: `useGameHost`, `useGamePlayer` for React apps
|
|
63
|
+
- **TypeScript Support**: Full type definitions included
|
|
64
|
+
- **Testing Utilities**: Mock Screen and Controller for unit testing
|
|
65
|
+
- **Multiple Formats**: ESM, CJS, and UMD builds
|
|
66
|
+
- **Zero Dependencies**: Peer dependencies only (React, Socket.IO)
|
|
67
|
+
|
|
68
|
+
## API Reference
|
|
69
|
+
|
|
70
|
+
### SmoreScreen
|
|
71
|
+
|
|
72
|
+
Screen-side game controller.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const screen = new SmoreScreen({
|
|
76
|
+
gameId: string;
|
|
77
|
+
listeners?: Record<string, (playerIndex: number, data: any) => void>;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Methods
|
|
81
|
+
screen.broadcast(event: string, data: any): void
|
|
82
|
+
screen.sendToPlayer(playerIndex: number, event: string, data: any): void
|
|
83
|
+
screen.on(event: string, callback: Function): void
|
|
84
|
+
screen.off(event: string, callback: Function): void
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### SmoreController
|
|
88
|
+
|
|
89
|
+
Controller-side app.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const controller = new SmoreController({
|
|
93
|
+
gameId: string;
|
|
94
|
+
listeners?: Record<string, (data: any) => void>;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Methods
|
|
98
|
+
controller.send(event: string, data: any): void
|
|
99
|
+
controller.on(event: string, callback: Function): void
|
|
100
|
+
controller.off(event: string, callback: Function): void
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### React Hooks
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { useGameHost, useGamePlayer } from '@smoregg/sdk';
|
|
107
|
+
|
|
108
|
+
// Screen
|
|
109
|
+
const { room, broadcast, sendToPlayer } = useGameHost({
|
|
110
|
+
gameId: 'my-game',
|
|
111
|
+
onInput: {
|
|
112
|
+
tap: (playerIndex, data) => { /* ... */ }
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Controller
|
|
117
|
+
const { emit, room } = useGamePlayer({
|
|
118
|
+
gameId: 'my-game',
|
|
119
|
+
listeners: {
|
|
120
|
+
'state-update': (state) => { /* ... */ }
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Backward Compatibility
|
|
126
|
+
|
|
127
|
+
The old `SmoreHost` and `SmorePlayer` names are still available as aliases:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// These still work (deprecated)
|
|
131
|
+
import { SmoreHost, SmorePlayer } from '@smoregg/sdk';
|
|
132
|
+
|
|
133
|
+
// Prefer the new names
|
|
134
|
+
import { SmoreScreen, SmoreController } from '@smoregg/sdk';
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Testing
|
|
138
|
+
|
|
139
|
+
The SDK provides comprehensive testing utilities for unit testing your game logic:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import { createMockScreen, createMockController } from '@smoregg/sdk';
|
|
143
|
+
|
|
144
|
+
// Create mock screen with players
|
|
145
|
+
const screen = createMockScreen<MyEvents>({
|
|
146
|
+
controllers: [
|
|
147
|
+
{ playerIndex: 0, nickname: 'Player 1', connected: true },
|
|
148
|
+
],
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Simulate player input
|
|
152
|
+
screen.simulateEvent(0, 'tap', { x: 100, y: 200 });
|
|
153
|
+
|
|
154
|
+
// Check what was broadcast
|
|
155
|
+
expect(screen.getBroadcasts()).toContainEqual({
|
|
156
|
+
event: 'score-update',
|
|
157
|
+
data: { scores: { 0: 10 } },
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
See [docs/testing.md](./docs/testing.md) for the full testing guide.
|
|
162
|
+
|
|
163
|
+
## Types
|
|
164
|
+
|
|
165
|
+
All types are exported from the main package:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import type {
|
|
169
|
+
Player,
|
|
170
|
+
PlayerDTO,
|
|
171
|
+
CharacterAppearance,
|
|
172
|
+
GameMetadata,
|
|
173
|
+
GameState,
|
|
174
|
+
InputCallback
|
|
175
|
+
} from '@smoregg/sdk';
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Building
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Development
|
|
182
|
+
pnpm typecheck
|
|
183
|
+
|
|
184
|
+
# Build all formats (ESM, CJS, UMD)
|
|
185
|
+
pnpm build
|
|
186
|
+
|
|
187
|
+
# Clean
|
|
188
|
+
pnpm clean
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Publishing
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
pnpm publish:npm
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT (C) S'MORE Team
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var PostMessageTransport = require('./transport/PostMessageTransport.cjs');
|
|
4
|
+
var protocol = require('./transport/protocol.cjs');
|
|
5
|
+
|
|
6
|
+
const SYSTEM_PREFIX = "smore:";
|
|
7
|
+
const SYSTEM_EVENTS = {
|
|
8
|
+
PLAYER_JOIN: `${SYSTEM_PREFIX}player-join`,
|
|
9
|
+
PLAYER_LEAVE: `${SYSTEM_PREFIX}player-leave`
|
|
10
|
+
};
|
|
11
|
+
const DEFAULT_TIMEOUT = 1e4;
|
|
12
|
+
class SmoreSDKError extends Error {
|
|
13
|
+
code;
|
|
14
|
+
cause;
|
|
15
|
+
details;
|
|
16
|
+
constructor(code, message, options) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "SmoreSDKError";
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.cause = options?.cause;
|
|
21
|
+
this.details = options?.details;
|
|
22
|
+
const ErrorWithCapture = Error;
|
|
23
|
+
if (typeof ErrorWithCapture.captureStackTrace === "function") {
|
|
24
|
+
ErrorWithCapture.captureStackTrace(this, SmoreSDKError);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
toSmoreError() {
|
|
28
|
+
return {
|
|
29
|
+
code: this.code,
|
|
30
|
+
message: this.message,
|
|
31
|
+
cause: this.cause,
|
|
32
|
+
details: this.details
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const EVENT_NAME_REGEX = /^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;
|
|
37
|
+
function validateEventName(event) {
|
|
38
|
+
if (!event || typeof event !== "string") {
|
|
39
|
+
throw new SmoreSDKError("INVALID_EVENT", "Event name must be a non-empty string");
|
|
40
|
+
}
|
|
41
|
+
if (!EVENT_NAME_REGEX.test(event)) {
|
|
42
|
+
throw new SmoreSDKError(
|
|
43
|
+
"INVALID_EVENT",
|
|
44
|
+
`Invalid event name "${event}". Event names must:
|
|
45
|
+
- Start with a letter (a-z, A-Z)
|
|
46
|
+
- Only contain letters, numbers, hyphens (-), and underscores (_)
|
|
47
|
+
- End with a letter or number`,
|
|
48
|
+
{ details: { event } }
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function createLogger(options) {
|
|
53
|
+
const enabled = typeof options === "boolean" ? options : options?.enabled ?? false;
|
|
54
|
+
const level = (typeof options === "object" ? options.level : void 0) ?? "debug";
|
|
55
|
+
const prefix = (typeof options === "object" ? options.prefix : void 0) ?? "[SmoreController]";
|
|
56
|
+
const customLogger = typeof options === "object" ? options.logger : void 0;
|
|
57
|
+
const levelPriority = {
|
|
58
|
+
debug: 0,
|
|
59
|
+
info: 1,
|
|
60
|
+
warn: 2,
|
|
61
|
+
error: 3
|
|
62
|
+
};
|
|
63
|
+
const shouldLog = (msgLevel) => {
|
|
64
|
+
if (!enabled) return false;
|
|
65
|
+
return levelPriority[msgLevel] >= levelPriority[level];
|
|
66
|
+
};
|
|
67
|
+
const log = (msgLevel, message, data) => {
|
|
68
|
+
if (!shouldLog(msgLevel)) return;
|
|
69
|
+
if (customLogger) {
|
|
70
|
+
customLogger(msgLevel, message, data);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const fullMessage = `${prefix} ${message}`;
|
|
74
|
+
const consoleFn = console[msgLevel] ?? console.log;
|
|
75
|
+
if (data !== void 0) {
|
|
76
|
+
consoleFn(fullMessage, data);
|
|
77
|
+
} else {
|
|
78
|
+
consoleFn(fullMessage);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
return {
|
|
82
|
+
debug: (msg, data) => log("debug", msg, data),
|
|
83
|
+
info: (msg, data) => log("info", msg, data),
|
|
84
|
+
warn: (msg, data) => log("warn", msg, data),
|
|
85
|
+
error: (msg, data) => log("error", msg, data)
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
class ControllerImpl {
|
|
89
|
+
transport = null;
|
|
90
|
+
config;
|
|
91
|
+
logger;
|
|
92
|
+
_roomCode = "";
|
|
93
|
+
_myIndex = -1;
|
|
94
|
+
_isLeader = false;
|
|
95
|
+
_isReady = false;
|
|
96
|
+
_isDestroyed = false;
|
|
97
|
+
boundMessageHandler = null;
|
|
98
|
+
registeredHandlers = [];
|
|
99
|
+
eventListeners = /* @__PURE__ */ new Map();
|
|
100
|
+
constructor(config = {}) {
|
|
101
|
+
this.config = config;
|
|
102
|
+
this.logger = createLogger(config.debug);
|
|
103
|
+
if (config.listeners) {
|
|
104
|
+
for (const event of Object.keys(config.listeners)) {
|
|
105
|
+
validateEventName(event);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
// Properties (readonly)
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
get myIndex() {
|
|
113
|
+
return this._myIndex;
|
|
114
|
+
}
|
|
115
|
+
get isLeader() {
|
|
116
|
+
return this._isLeader;
|
|
117
|
+
}
|
|
118
|
+
get roomCode() {
|
|
119
|
+
return this._roomCode;
|
|
120
|
+
}
|
|
121
|
+
get isReady() {
|
|
122
|
+
return this._isReady;
|
|
123
|
+
}
|
|
124
|
+
get isDestroyed() {
|
|
125
|
+
return this._isDestroyed;
|
|
126
|
+
}
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// Initialization
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
async initialize() {
|
|
131
|
+
const parentOrigin = this.config.parentOrigin ?? "*";
|
|
132
|
+
const timeout = this.config.timeout ?? DEFAULT_TIMEOUT;
|
|
133
|
+
this.logger.debug("Initializing controller...", { parentOrigin, timeout });
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
const timeoutId = setTimeout(() => {
|
|
136
|
+
this.cleanup();
|
|
137
|
+
const error = new SmoreSDKError(
|
|
138
|
+
"TIMEOUT",
|
|
139
|
+
`Controller initialization timed out after ${timeout}ms. Make sure the parent window sends smore:init message.`,
|
|
140
|
+
{ details: { timeout } }
|
|
141
|
+
);
|
|
142
|
+
this.handleError(error);
|
|
143
|
+
reject(error);
|
|
144
|
+
}, timeout);
|
|
145
|
+
this.boundMessageHandler = (e) => {
|
|
146
|
+
if (parentOrigin !== "*" && e.origin !== parentOrigin) return;
|
|
147
|
+
const msg = e.data;
|
|
148
|
+
if (!protocol.isSmoreMessage(msg)) return;
|
|
149
|
+
if (msg.type === "smore:init") {
|
|
150
|
+
clearTimeout(timeoutId);
|
|
151
|
+
this.handleInit(msg, parentOrigin, resolve, reject);
|
|
152
|
+
} else if (msg.type === "smore:update") {
|
|
153
|
+
this.handleUpdate(msg);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
window.addEventListener("message", this.boundMessageHandler);
|
|
157
|
+
this.logger.debug("Sending smore:ready to parent");
|
|
158
|
+
window.parent.postMessage({ type: "smore:ready" }, parentOrigin);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
handleInit(msg, parentOrigin, resolve, reject) {
|
|
162
|
+
const initData = msg.payload;
|
|
163
|
+
this.logger.debug("Received smore:init", initData);
|
|
164
|
+
if (initData.side !== "player") {
|
|
165
|
+
const error = new SmoreSDKError(
|
|
166
|
+
"INIT_FAILED",
|
|
167
|
+
`Controller received init for wrong side: ${initData.side}`,
|
|
168
|
+
{ details: { side: initData.side } }
|
|
169
|
+
);
|
|
170
|
+
this.handleError(error);
|
|
171
|
+
reject(error);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (initData.myIndex === void 0) {
|
|
175
|
+
const error = new SmoreSDKError(
|
|
176
|
+
"INIT_FAILED",
|
|
177
|
+
"Missing myIndex in init payload",
|
|
178
|
+
{ details: initData }
|
|
179
|
+
);
|
|
180
|
+
this.handleError(error);
|
|
181
|
+
reject(error);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
this.transport = new PostMessageTransport.PostMessageTransport(parentOrigin);
|
|
185
|
+
this._roomCode = initData.roomCode;
|
|
186
|
+
this._myIndex = initData.myIndex;
|
|
187
|
+
this._isLeader = initData.isLeader ?? false;
|
|
188
|
+
this.setupEventHandlers();
|
|
189
|
+
this._isReady = true;
|
|
190
|
+
this.logger.info("Controller ready", {
|
|
191
|
+
roomCode: this._roomCode,
|
|
192
|
+
myIndex: this._myIndex,
|
|
193
|
+
isLeader: this._isLeader
|
|
194
|
+
});
|
|
195
|
+
this.config.onReady?.();
|
|
196
|
+
resolve();
|
|
197
|
+
}
|
|
198
|
+
handleUpdate(msg) {
|
|
199
|
+
const updateData = msg.payload;
|
|
200
|
+
this.logger.debug("Received smore:update", updateData);
|
|
201
|
+
}
|
|
202
|
+
setupEventHandlers() {
|
|
203
|
+
if (!this.transport) return;
|
|
204
|
+
this.registerHandler(
|
|
205
|
+
SYSTEM_EVENTS.PLAYER_JOIN,
|
|
206
|
+
(data) => {
|
|
207
|
+
const playerIndex = data.player?.playerIndex ?? data.playerIndex;
|
|
208
|
+
if (playerIndex !== void 0) {
|
|
209
|
+
this.logger.debug("Player joined", { playerIndex });
|
|
210
|
+
this.config.onControllerJoin?.(playerIndex, data.player);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
this.registerHandler(
|
|
215
|
+
SYSTEM_EVENTS.PLAYER_LEAVE,
|
|
216
|
+
(data) => {
|
|
217
|
+
const playerIndex = data.player?.playerIndex ?? data.playerIndex;
|
|
218
|
+
if (playerIndex !== void 0) {
|
|
219
|
+
this.logger.debug("Player left", { playerIndex });
|
|
220
|
+
this.config.onControllerLeave?.(playerIndex);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
if (this.config.listeners) {
|
|
225
|
+
for (const [event, handler] of Object.entries(this.config.listeners)) {
|
|
226
|
+
if (!handler) continue;
|
|
227
|
+
this.registerHandler(event, (data) => {
|
|
228
|
+
this.logReceive(event, data);
|
|
229
|
+
handler(data);
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
registerHandler(event, handler) {
|
|
235
|
+
if (!this.transport) return;
|
|
236
|
+
this.transport.on(event, handler);
|
|
237
|
+
this.registeredHandlers.push({ event, handler });
|
|
238
|
+
}
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
// Communication Methods
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
send(event, data) {
|
|
243
|
+
this.ensureReady("send");
|
|
244
|
+
validateEventName(event);
|
|
245
|
+
this.logSend(event, data);
|
|
246
|
+
this.transport.emit(event, data);
|
|
247
|
+
}
|
|
248
|
+
sendRaw(event, data) {
|
|
249
|
+
this.ensureReady("sendRaw");
|
|
250
|
+
validateEventName(event);
|
|
251
|
+
this.logSend(event, data);
|
|
252
|
+
this.transport.emit(event, data);
|
|
253
|
+
}
|
|
254
|
+
// ---------------------------------------------------------------------------
|
|
255
|
+
// Event Subscription
|
|
256
|
+
// ---------------------------------------------------------------------------
|
|
257
|
+
on(event, handler) {
|
|
258
|
+
validateEventName(event);
|
|
259
|
+
let listeners = this.eventListeners.get(event);
|
|
260
|
+
if (!listeners) {
|
|
261
|
+
listeners = /* @__PURE__ */ new Set();
|
|
262
|
+
this.eventListeners.set(event, listeners);
|
|
263
|
+
}
|
|
264
|
+
listeners.add(handler);
|
|
265
|
+
const transportHandler = (data) => {
|
|
266
|
+
this.logReceive(event, data);
|
|
267
|
+
handler(data);
|
|
268
|
+
};
|
|
269
|
+
if (this.transport) {
|
|
270
|
+
this.transport.on(event, transportHandler);
|
|
271
|
+
this.registeredHandlers.push({ event, handler: transportHandler });
|
|
272
|
+
}
|
|
273
|
+
return () => {
|
|
274
|
+
listeners?.delete(handler);
|
|
275
|
+
if (listeners?.size === 0) {
|
|
276
|
+
this.eventListeners.delete(event);
|
|
277
|
+
}
|
|
278
|
+
this.transport?.off(event, transportHandler);
|
|
279
|
+
this.registeredHandlers = this.registeredHandlers.filter(
|
|
280
|
+
(h) => h.handler !== transportHandler
|
|
281
|
+
);
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
once(event, handler) {
|
|
285
|
+
const unsubscribe = this.on(event, ((data) => {
|
|
286
|
+
unsubscribe();
|
|
287
|
+
handler(data);
|
|
288
|
+
}));
|
|
289
|
+
return unsubscribe;
|
|
290
|
+
}
|
|
291
|
+
off(event, handler) {
|
|
292
|
+
if (!handler) {
|
|
293
|
+
this.eventListeners.delete(event);
|
|
294
|
+
this.transport?.off(event);
|
|
295
|
+
this.registeredHandlers = this.registeredHandlers.filter((h) => h.event !== event);
|
|
296
|
+
} else {
|
|
297
|
+
const listeners = this.eventListeners.get(event);
|
|
298
|
+
listeners?.delete(handler);
|
|
299
|
+
if (listeners?.size === 0) {
|
|
300
|
+
this.eventListeners.delete(event);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
// ---------------------------------------------------------------------------
|
|
305
|
+
// Cleanup
|
|
306
|
+
// ---------------------------------------------------------------------------
|
|
307
|
+
destroy() {
|
|
308
|
+
if (this._isDestroyed) return;
|
|
309
|
+
this.logger.info("Destroying controller");
|
|
310
|
+
this.cleanup();
|
|
311
|
+
this._isDestroyed = true;
|
|
312
|
+
}
|
|
313
|
+
cleanup() {
|
|
314
|
+
this._isReady = false;
|
|
315
|
+
for (const { event, handler } of this.registeredHandlers) {
|
|
316
|
+
this.transport?.off(event, handler);
|
|
317
|
+
}
|
|
318
|
+
this.registeredHandlers = [];
|
|
319
|
+
this.eventListeners.clear();
|
|
320
|
+
if (this.transport) {
|
|
321
|
+
this.transport.destroy();
|
|
322
|
+
this.transport = null;
|
|
323
|
+
}
|
|
324
|
+
if (this.boundMessageHandler) {
|
|
325
|
+
window.removeEventListener("message", this.boundMessageHandler);
|
|
326
|
+
this.boundMessageHandler = null;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// ---------------------------------------------------------------------------
|
|
330
|
+
// Private Helpers
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
ensureReady(method) {
|
|
333
|
+
if (this._isDestroyed) {
|
|
334
|
+
throw new SmoreSDKError(
|
|
335
|
+
"DESTROYED",
|
|
336
|
+
`Cannot call ${method}() after destroy()`,
|
|
337
|
+
{ details: { method } }
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
if (!this._isReady || !this.transport) {
|
|
341
|
+
throw new SmoreSDKError(
|
|
342
|
+
"NOT_READY",
|
|
343
|
+
`Cannot call ${method}() before controller is ready. Use await createController() or wait for onReady callback.`,
|
|
344
|
+
{ details: { method, isReady: this._isReady } }
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
handleError(error) {
|
|
349
|
+
if (this.config.onError) {
|
|
350
|
+
this.config.onError(error.toSmoreError());
|
|
351
|
+
} else {
|
|
352
|
+
this.logger.error(error.message, error.details);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
logSend(event, data) {
|
|
356
|
+
const options = this.config.debug;
|
|
357
|
+
const shouldLog = typeof options === "object" ? options.logSend ?? true : Boolean(options);
|
|
358
|
+
if (shouldLog) {
|
|
359
|
+
this.logger.debug(`\u2192 SEND [${event}]`, data);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
logReceive(event, data) {
|
|
363
|
+
const options = this.config.debug;
|
|
364
|
+
const shouldLog = typeof options === "object" ? options.logReceive ?? true : Boolean(options);
|
|
365
|
+
if (shouldLog) {
|
|
366
|
+
this.logger.debug(`\u2190 RECV [${event}]`, data);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function createController(config) {
|
|
371
|
+
const controller = new ControllerImpl(config ?? {});
|
|
372
|
+
const promise = controller.initialize().then(() => controller);
|
|
373
|
+
promise.instance = controller;
|
|
374
|
+
return promise;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
exports.SmoreSDKError = SmoreSDKError;
|
|
378
|
+
exports.createController = createController;
|
|
379
|
+
//# sourceMappingURL=controller.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.cjs","sources":["../../src/controller.ts"],"sourcesContent":["/**\n * createController - Factory function for creating a Controller instance.\n *\n * Returns a Promise that resolves when the controller is ready and initialized.\n * Uses PostMessageTransport for iframe communication with parent window.\n *\n * @example Promise-based (recommended)\n * ```ts\n * const controller = await createController<MyEvents>({\n * listeners: {\n * 'phase-update': (data) => setPhase(data.phase),\n * },\n * });\n *\n * console.log(`Ready! My index: ${controller.myIndex}`);\n * controller.send('tap', { x: 100, y: 200 });\n * ```\n *\n * @example Callback-based\n * ```ts\n * const controller = createController<MyEvents>({\n * onReady: () => {\n * console.log('Ready!');\n * },\n * listeners: { ... },\n * });\n * // Use controller.instance for immediate access\n * ```\n */\n\nimport type {\n Controller,\n ControllerConfig,\n ControllerEventHandler,\n ControllerInfo,\n DebugOptions,\n EventData,\n EventMap,\n EventNames,\n LogLevel,\n PlayerIndex,\n RoomCode,\n SmoreError,\n SmoreErrorCode,\n} from './types';\nimport { PostMessageTransport } from './transport/PostMessageTransport';\nimport type { TransportEventHandler } from './transport/types';\nimport {\n isSmoreMessage,\n type SmoreInitMessage,\n type SmoreUpdateMessage,\n} from './transport/protocol';\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst SYSTEM_PREFIX = 'smore:';\n\nconst SYSTEM_EVENTS = {\n READY: `${SYSTEM_PREFIX}ready`,\n PLAYER_JOIN: `${SYSTEM_PREFIX}player-join`,\n PLAYER_LEAVE: `${SYSTEM_PREFIX}player-leave`,\n} as const;\n\nconst DEFAULT_TIMEOUT = 10000;\n\n// =============================================================================\n// ERROR CLASS\n// =============================================================================\n\n/**\n * Custom error class for SDK errors.\n */\nexport class SmoreSDKError extends Error {\n readonly code: SmoreErrorCode;\n readonly cause?: Error;\n readonly details?: Record<string, unknown>;\n\n constructor(\n code: SmoreErrorCode,\n message: string,\n options?: {\n cause?: Error;\n details?: Record<string, unknown>;\n },\n ) {\n super(message);\n this.name = 'SmoreSDKError';\n this.code = code;\n this.cause = options?.cause;\n this.details = options?.details;\n\n // Maintain proper stack trace in V8 engines\n const ErrorWithCapture = Error as typeof Error & {\n captureStackTrace?: (target: object, constructor?: Function) => void;\n };\n if (typeof ErrorWithCapture.captureStackTrace === 'function') {\n ErrorWithCapture.captureStackTrace(this, SmoreSDKError);\n }\n }\n\n toSmoreError(): SmoreError {\n return {\n code: this.code,\n message: this.message,\n cause: this.cause,\n details: this.details,\n };\n }\n}\n\n// =============================================================================\n// VALIDATION\n// =============================================================================\n\nconst EVENT_NAME_REGEX = /^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;\n\nfunction validateEventName(event: string): void {\n if (!event || typeof event !== 'string') {\n throw new SmoreSDKError('INVALID_EVENT', 'Event name must be a non-empty string');\n }\n if (!EVENT_NAME_REGEX.test(event)) {\n throw new SmoreSDKError(\n 'INVALID_EVENT',\n `Invalid event name \"${event}\". Event names must:\\n` +\n ` - Start with a letter (a-z, A-Z)\\n` +\n ` - Only contain letters, numbers, hyphens (-), and underscores (_)\\n` +\n ` - End with a letter or number`,\n { details: { event } },\n );\n }\n}\n\n// =============================================================================\n// DEBUG LOGGER\n// =============================================================================\n\ninterface Logger {\n debug(message: string, data?: unknown): void;\n info(message: string, data?: unknown): void;\n warn(message: string, data?: unknown): void;\n error(message: string, data?: unknown): void;\n}\n\nfunction createLogger(options: boolean | DebugOptions | undefined): Logger {\n const enabled = typeof options === 'boolean' ? options : options?.enabled ?? false;\n const level = (typeof options === 'object' ? options.level : undefined) ?? 'debug';\n const prefix = (typeof options === 'object' ? options.prefix : undefined) ?? '[SmoreController]';\n const customLogger = typeof options === 'object' ? options.logger : undefined;\n\n const levelPriority: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n };\n\n const shouldLog = (msgLevel: LogLevel): boolean => {\n if (!enabled) return false;\n return levelPriority[msgLevel] >= levelPriority[level];\n };\n\n const log = (msgLevel: LogLevel, message: string, data?: unknown): void => {\n if (!shouldLog(msgLevel)) return;\n\n if (customLogger) {\n customLogger(msgLevel, message, data);\n return;\n }\n\n const fullMessage = `${prefix} ${message}`;\n const consoleFn = console[msgLevel] ?? console.log;\n\n if (data !== undefined) {\n consoleFn(fullMessage, data);\n } else {\n consoleFn(fullMessage);\n }\n };\n\n return {\n debug: (msg, data) => log('debug', msg, data),\n info: (msg, data) => log('info', msg, data),\n warn: (msg, data) => log('warn', msg, data),\n error: (msg, data) => log('error', msg, data),\n };\n}\n\n// =============================================================================\n// CONTROLLER IMPLEMENTATION\n// =============================================================================\n\nclass ControllerImpl<TEvents extends EventMap> implements Controller<TEvents> {\n private transport: PostMessageTransport | null = null;\n private config: ControllerConfig<TEvents>;\n private logger: Logger;\n private _roomCode: RoomCode = '';\n private _myIndex: PlayerIndex = -1;\n private _isLeader: boolean = false;\n private _isReady: boolean = false;\n private _isDestroyed: boolean = false;\n private boundMessageHandler: ((e: MessageEvent) => void) | null = null;\n private registeredHandlers: Array<{ event: string; handler: TransportEventHandler }> = [];\n private eventListeners = new Map<string, Set<ControllerEventHandler<unknown>>>();\n\n constructor(config: ControllerConfig<TEvents> = {}) {\n this.config = config;\n this.logger = createLogger(config.debug);\n\n // Validate event names in listeners\n if (config.listeners) {\n for (const event of Object.keys(config.listeners)) {\n validateEventName(event);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Properties (readonly)\n // ---------------------------------------------------------------------------\n\n get myIndex(): PlayerIndex {\n return this._myIndex;\n }\n\n get isLeader(): boolean {\n return this._isLeader;\n }\n\n get roomCode(): RoomCode {\n return this._roomCode;\n }\n\n get isReady(): boolean {\n return this._isReady;\n }\n\n get isDestroyed(): boolean {\n return this._isDestroyed;\n }\n\n // ---------------------------------------------------------------------------\n // Initialization\n // ---------------------------------------------------------------------------\n\n async initialize(): Promise<void> {\n const parentOrigin = this.config.parentOrigin ?? '*';\n const timeout = this.config.timeout ?? DEFAULT_TIMEOUT;\n\n this.logger.debug('Initializing controller...', { parentOrigin, timeout });\n\n return new Promise<void>((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.cleanup();\n const error = new SmoreSDKError(\n 'TIMEOUT',\n `Controller initialization timed out after ${timeout}ms. ` +\n `Make sure the parent window sends smore:init message.`,\n { details: { timeout } },\n );\n this.handleError(error);\n reject(error);\n }, timeout);\n\n // Listen for init message from parent\n this.boundMessageHandler = (e: MessageEvent) => {\n if (parentOrigin !== '*' && e.origin !== parentOrigin) return;\n\n const msg = e.data;\n if (!isSmoreMessage(msg)) return;\n\n if (msg.type === 'smore:init') {\n clearTimeout(timeoutId);\n this.handleInit(msg as SmoreInitMessage, parentOrigin, resolve, reject);\n } else if (msg.type === 'smore:update') {\n this.handleUpdate(msg as SmoreUpdateMessage);\n }\n };\n\n window.addEventListener('message', this.boundMessageHandler);\n\n // Signal ready to parent\n this.logger.debug('Sending smore:ready to parent');\n window.parent.postMessage({ type: 'smore:ready' }, parentOrigin);\n });\n }\n\n private handleInit(\n msg: SmoreInitMessage,\n parentOrigin: string,\n resolve: () => void,\n reject: (err: Error) => void,\n ): void {\n const initData = msg.payload;\n\n this.logger.debug('Received smore:init', initData);\n\n if (initData.side !== 'player') {\n const error = new SmoreSDKError(\n 'INIT_FAILED',\n `Controller received init for wrong side: ${initData.side}`,\n { details: { side: initData.side } },\n );\n this.handleError(error);\n reject(error);\n return;\n }\n\n if (initData.myIndex === undefined) {\n const error = new SmoreSDKError(\n 'INIT_FAILED',\n 'Missing myIndex in init payload',\n { details: initData },\n );\n this.handleError(error);\n reject(error);\n return;\n }\n\n // Initialize transport\n this.transport = new PostMessageTransport(parentOrigin);\n this._roomCode = initData.roomCode;\n this._myIndex = initData.myIndex;\n this._isLeader = initData.isLeader ?? false;\n\n this.setupEventHandlers();\n\n this._isReady = true;\n this.logger.info('Controller ready', {\n roomCode: this._roomCode,\n myIndex: this._myIndex,\n isLeader: this._isLeader,\n });\n\n this.config.onReady?.();\n resolve();\n }\n\n private handleUpdate(msg: SmoreUpdateMessage): void {\n const updateData = msg.payload;\n this.logger.debug('Received smore:update', updateData);\n\n // Future: handle leader changes, player list updates, etc.\n }\n\n private setupEventHandlers(): void {\n if (!this.transport) return;\n\n // System events: player join/leave\n this.registerHandler(\n SYSTEM_EVENTS.PLAYER_JOIN,\n (data: { player?: ControllerInfo; playerIndex?: number }) => {\n const playerIndex = data.player?.playerIndex ?? data.playerIndex;\n if (playerIndex !== undefined) {\n this.logger.debug('Player joined', { playerIndex });\n this.config.onControllerJoin?.(playerIndex, data.player as ControllerInfo);\n }\n },\n );\n\n this.registerHandler(\n SYSTEM_EVENTS.PLAYER_LEAVE,\n (data: { player?: { playerIndex?: number }; playerIndex?: number }) => {\n const playerIndex = data.player?.playerIndex ?? data.playerIndex;\n if (playerIndex !== undefined) {\n this.logger.debug('Player left', { playerIndex });\n this.config.onControllerLeave?.(playerIndex);\n }\n },\n );\n\n // User event listeners from config\n if (this.config.listeners) {\n for (const [event, handler] of Object.entries(this.config.listeners)) {\n if (!handler) continue;\n\n this.registerHandler(event, (data: unknown) => {\n this.logReceive(event, data);\n (handler as ControllerEventHandler<unknown>)(data);\n });\n }\n }\n }\n\n private registerHandler(event: string, handler: TransportEventHandler): void {\n if (!this.transport) return;\n this.transport.on(event, handler);\n this.registeredHandlers.push({ event, handler });\n }\n\n // ---------------------------------------------------------------------------\n // Communication Methods\n // ---------------------------------------------------------------------------\n\n send<K extends EventNames<TEvents>>(event: K, data: EventData<TEvents, K>): void {\n this.ensureReady('send');\n validateEventName(event);\n\n this.logSend(event, data);\n this.transport!.emit(event, data);\n }\n\n sendRaw(event: string, data?: unknown): void {\n this.ensureReady('sendRaw');\n validateEventName(event);\n\n this.logSend(event, data);\n this.transport!.emit(event, data);\n }\n\n // ---------------------------------------------------------------------------\n // Event Subscription\n // ---------------------------------------------------------------------------\n\n on<K extends EventNames<TEvents>>(\n event: K,\n handler: ControllerEventHandler<EventData<TEvents, K>>,\n ): () => void {\n validateEventName(event);\n\n // Add to local listeners map\n let listeners = this.eventListeners.get(event);\n if (!listeners) {\n listeners = new Set();\n this.eventListeners.set(event, listeners);\n }\n listeners.add(handler as ControllerEventHandler<unknown>);\n\n // Register with transport if ready\n const transportHandler: TransportEventHandler = (data: unknown) => {\n this.logReceive(event, data);\n (handler as ControllerEventHandler<unknown>)(data);\n };\n\n if (this.transport) {\n this.transport.on(event, transportHandler);\n this.registeredHandlers.push({ event, handler: transportHandler });\n }\n\n // Return unsubscribe function\n return () => {\n listeners?.delete(handler as ControllerEventHandler<unknown>);\n if (listeners?.size === 0) {\n this.eventListeners.delete(event);\n }\n this.transport?.off(event, transportHandler);\n this.registeredHandlers = this.registeredHandlers.filter(\n (h) => h.handler !== transportHandler,\n );\n };\n }\n\n once<K extends EventNames<TEvents>>(\n event: K,\n handler: ControllerEventHandler<EventData<TEvents, K>>,\n ): () => void {\n const unsubscribe = this.on(event, ((data: EventData<TEvents, K>) => {\n unsubscribe();\n handler(data);\n }) as ControllerEventHandler<EventData<TEvents, K>>);\n return unsubscribe;\n }\n\n off<K extends EventNames<TEvents>>(\n event: K,\n handler?: ControllerEventHandler<EventData<TEvents, K>>,\n ): void {\n if (!handler) {\n // Remove all listeners for this event\n this.eventListeners.delete(event);\n this.transport?.off(event);\n this.registeredHandlers = this.registeredHandlers.filter((h) => h.event !== event);\n } else {\n // Remove specific handler\n const listeners = this.eventListeners.get(event);\n listeners?.delete(handler as ControllerEventHandler<unknown>);\n if (listeners?.size === 0) {\n this.eventListeners.delete(event);\n }\n // Note: Can't easily remove specific handler from transport without tracking\n // This is a limitation of the current transport interface\n }\n }\n\n // ---------------------------------------------------------------------------\n // Cleanup\n // ---------------------------------------------------------------------------\n\n destroy(): void {\n if (this._isDestroyed) return;\n\n this.logger.info('Destroying controller');\n this.cleanup();\n this._isDestroyed = true;\n }\n\n private cleanup(): void {\n this._isReady = false;\n\n // Remove all registered handlers\n for (const { event, handler } of this.registeredHandlers) {\n this.transport?.off(event, handler);\n }\n this.registeredHandlers = [];\n\n // Clear event listeners\n this.eventListeners.clear();\n\n // Destroy transport\n if (this.transport) {\n this.transport.destroy();\n this.transport = null;\n }\n\n // Remove message listener\n if (this.boundMessageHandler) {\n window.removeEventListener('message', this.boundMessageHandler);\n this.boundMessageHandler = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private Helpers\n // ---------------------------------------------------------------------------\n\n private ensureReady(method: string): void {\n if (this._isDestroyed) {\n throw new SmoreSDKError(\n 'DESTROYED',\n `Cannot call ${method}() after destroy()`,\n { details: { method } },\n );\n }\n if (!this._isReady || !this.transport) {\n throw new SmoreSDKError(\n 'NOT_READY',\n `Cannot call ${method}() before controller is ready. ` +\n `Use await createController() or wait for onReady callback.`,\n { details: { method, isReady: this._isReady } },\n );\n }\n }\n\n private handleError(error: SmoreSDKError): void {\n if (this.config.onError) {\n this.config.onError(error.toSmoreError());\n } else {\n this.logger.error(error.message, error.details);\n }\n }\n\n private logSend(event: string, data?: unknown): void {\n const options = this.config.debug;\n const shouldLog =\n typeof options === 'object' ? (options.logSend ?? true) : Boolean(options);\n if (shouldLog) {\n this.logger.debug(`→ SEND [${event}]`, data);\n }\n }\n\n private logReceive(event: string, data?: unknown): void {\n const options = this.config.debug;\n const shouldLog =\n typeof options === 'object' ? (options.logReceive ?? true) : Boolean(options);\n if (shouldLog) {\n this.logger.debug(`← RECV [${event}]`, data);\n }\n }\n}\n\n// =============================================================================\n// FACTORY FUNCTION\n// =============================================================================\n\n/**\n * Create a Controller instance for the player/phone side of your game.\n *\n * Returns a Promise that resolves when the controller is ready.\n * The returned object also has an `instance` property for immediate access.\n *\n * @template TEvents - Event map type for type-safe events\n * @param config - Controller configuration\n * @returns Promise that resolves to the Controller instance when ready\n *\n * @example Promise-based (recommended)\n * ```ts\n * const controller = await createController<MyEvents>({\n * listeners: {\n * 'phase-update': (data) => setPhase(data.phase),\n * },\n * });\n *\n * controller.send('tap', { x: 100, y: 200 });\n * ```\n *\n * @example Callback-based\n * ```ts\n * const result = createController<MyEvents>({\n * onReady: () => {\n * result.instance.send('ready', {});\n * },\n * listeners: { ... },\n * });\n * ```\n */\nexport function createController<TEvents extends EventMap = EventMap>(\n config?: ControllerConfig<TEvents>,\n): Promise<Controller<TEvents>> & { instance: Controller<TEvents> } {\n const controller = new ControllerImpl<TEvents>(config ?? {});\n\n const promise = controller.initialize().then(() => controller as Controller<TEvents>);\n\n // Attach instance property for immediate access\n (promise as Promise<Controller<TEvents>> & { instance: Controller<TEvents> }).instance =\n controller;\n\n return promise as Promise<Controller<TEvents>> & { instance: Controller<TEvents> };\n}\n"],"names":["isSmoreMessage","PostMessageTransport"],"mappings":"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"}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var screen = require('./screen.cjs');
|
|
4
|
+
var controller = require('./controller.cjs');
|
|
5
5
|
var DirectTransport = require('./transport/DirectTransport.cjs');
|
|
6
6
|
var PostMessageTransport = require('./transport/PostMessageTransport.cjs');
|
|
7
7
|
var events = require('./events.cjs');
|
|
8
|
+
var testing = require('./testing.cjs');
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
exports.
|
|
12
|
-
exports.
|
|
12
|
+
exports.SmoreSDKError = screen.SmoreSDKError;
|
|
13
|
+
exports.createScreen = screen.createScreen;
|
|
14
|
+
exports.createController = controller.createController;
|
|
13
15
|
exports.DirectTransport = DirectTransport.DirectTransport;
|
|
14
16
|
exports.PostMessageTransport = PostMessageTransport.PostMessageTransport;
|
|
15
17
|
exports.SMORE_EVENTS = events.SMORE_EVENTS;
|
|
16
18
|
exports.isSystemEvent = events.isSystemEvent;
|
|
17
19
|
exports.validateUserEvent = events.validateUserEvent;
|
|
20
|
+
exports.createMockController = testing.createMockController;
|
|
21
|
+
exports.createMockScreen = testing.createMockScreen;
|
|
18
22
|
//# sourceMappingURL=index.cjs.map
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;"}
|