@puzzmo/sdk 1.0.10 → 1.0.11

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
@@ -127,6 +127,49 @@ sdk.gameCompleted(metrics, {
127
127
 
128
128
  The SDK automatically adds `points` and `time` deeds.
129
129
 
130
+ ## On-Screen Keyboard
131
+
132
+ For games that need text input on touch devices, the SDK can show Puzzmo's on-screen keyboard.
133
+ The keyboard is only visible on touch devices — calling these methods on desktop is a no-op.
134
+
135
+ ```ts
136
+ import { createPuzzmoSDK, defaultKeyboardConfig } from "@puzzmo/sdk"
137
+
138
+ const sdk = createPuzzmoSDK()
139
+
140
+ // Show the keyboard when the player selects an input
141
+ sdk.keyboard.show(defaultKeyboardConfig)
142
+
143
+ // Listen for key presses
144
+ sdk.on("keyboardKeyPress", ({ key }) => {
145
+ if (key === "⌫") handleBackspace()
146
+ else if (key === "↵") handleEnter()
147
+ else handleLetter(key)
148
+ })
149
+
150
+ // Hide when input is dismissed
151
+ sdk.keyboard.hide()
152
+ ```
153
+
154
+ `defaultKeyboardConfig` is a standard QWERTY layout with Enter and Backspace. Customize it by spreading:
155
+
156
+ ```ts
157
+ // Disable letters that are no longer valid given the current game state
158
+ sdk.keyboard.show({ ...defaultKeyboardConfig, disabled: usedLetters })
159
+ ```
160
+
161
+ For games with a spatial input model (e.g. selecting a grid cell by dragging across the keyboard),
162
+ enable drag cursor support and listen for the additional events:
163
+
164
+ ```ts
165
+ sdk.keyboard.show({ ...defaultKeyboardConfig, supportsDragCursor: true })
166
+
167
+ sdk.on("keyboardCursorChange", ({ position }) => highlightCellAtPosition(position))
168
+ sdk.on("keyboardCursorEnd", () => confirmCellSelection())
169
+ ```
170
+
171
+ See the `KeyboardConfig` type export and the `add-keyboard-support` skill for full field documentation.
172
+
130
173
  ## App Integration
131
174
 
132
175
  For games to show a dynamic thumbnail, you will need an App Bundle
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./objectSpread2-C4RR_HMd.cjs`);function t(e){let t=e>=3600*1e3;return new Date(e).toISOString().slice(t?11:14,-1).split(`.`)[0]}function n(e=0,n=0){let r=e,i=n,a=0,o,s,c,l=()=>{var e;if(s===void 0)return r+i;if(o!==void 0)return o;let t=((e=c)==null?performance.now():e)-s-a;return r+i+t};return{_init:()=>{s===void 0&&(s=performance.now(),c=void 0)},_pause:()=>{c!==void 0||s===void 0||(c=performance.now())},_resume:()=>{c!==void 0&&(a+=performance.now()-c,c=void 0)},_reset:(e=0,t=0)=>{r=e,i=t,a=0,o=void 0,s=void 0,c=void 0},_conclude:()=>{if(c!==void 0){o=l();return}if(s===void 0){o=r+i;return}o=l()},timeMs:()=>l(),timeSecs:()=>l()/1e3,addedTimeMs:()=>i,addedTimeSecs:()=>i/1e3,timeWithoutPenaltySecs:()=>(l()-i)/1e3,addPenalty:e=>{i+=e},isPaused:()=>c!==void 0||s===void 0,isRunning:()=>s!==void 0&&c===void 0,display:()=>{let e=l()-i;return[t(Math.max(0,e)),i===0?``:t(i)]}}}function r(){let e=new Map;return typeof window<`u`&&window.addEventListener(`message`,t=>{var n;if(!(!(t==null||(n=t.data)==null)&&n.type))return;let r=t.data.type,i=e.get(r);if(i){var a,o;let e=(a=(o=t.data.data)==null?t.data.json:o)==null?{}:a;r!==`TIMER_TICK`&&r!==`TIMER_SYNC`&&console.log(`[Puzzmo SDK] received:`,r,e),i.forEach(t=>t(e))}}),{sendMessage:(e,t)=>{var n,r;let i={type:e,json:t,_:`p`,__:`mp`,private:!0};`parent`in window&&window.parent!==window&&window.parent.postMessage(i,`*`),window.postMessage(i,`*`),`webkit`in window&&!((n=window.webkit)==null||(n=n.messageHandlers)==null)&&n.app&&window.webkit.messageHandlers.app.postMessage(i),`puzzmoMessageString`in window&&window.puzzmoMessageString(JSON.stringify(i)),`ReactNativeWebView`in window&&(r=window.ReactNativeWebView)!=null&&r.postMessage&&window.ReactNativeWebView.postMessage(JSON.stringify(i)),e!==`TIMER_TICK`&&e!==`TIMER_SYNC`&&console.log(`[Puzzmo SDK] sent:`,e,t)},onMessage:(t,n)=>(e.has(t)||e.set(t,new Set),e.get(t).add(n),()=>{var r;(r=e.get(t))==null||r.delete(n)})}}var i=r();const a=(t={})=>{let r=null,a=null,o=()=>{var e;return r==null||(e=r.startOrFindGameplay)==null?void 0:e.gamePlayed},s=()=>{var e,t;return(e=(t=o())==null?void 0:t.id)==null?null:e},c=()=>{var e,t;return(e=(t=o())==null?void 0:t.puzzle.puzzle)==null?null:e},l=()=>{var e,t;return(e=(t=o())==null?void 0:t.boardState)==null?null:e},u=()=>{var e;return(e=r==null?void 0:r.theme)==null?null:e},d=()=>{var e,t;return(e=(t=o())==null?void 0:t.completed)==null?!1:e},f=new Map,p=n(),m=null,h=null,g=()=>{m||(m=setInterval(()=>{if(p.isPaused())return;let[e,t]=p.display();i.sendMessage(`TIMER_TICK`,{display:[e,t]})},500),h=setInterval(()=>{p.isPaused()||i.sendMessage(`TIMER_SYNC`,Math.floor(p.timeWithoutPenaltySecs()))},1e4))},_=()=>{m&&(clearInterval(m),m=null),h&&(clearInterval(h),h=null)},v=(e,t)=>{let n=f.get(e);n&&n.forEach(e=>e(t))};return i.onMessage(`START_GAME`,()=>{p._init(),g(),v(`start`)}),i.onMessage(`PAUSE_GAME`,()=>{p._pause(),v(`pause`)}),i.onMessage(`RESUME_GAME`,()=>{p._resume(),v(`resume`)}),i.onMessage(`SETTINGS_UPDATE`,e=>v(`settingsUpdate`,e)),i.onMessage(`RETRY_PUZZLE`,()=>{p._reset(),_(),v(`retry`)}),i.onMessage(`READY_DATA`,e=>{var t;let n=e;r=n;let i=(t=n.startOrFindGameplay)==null?void 0:t.gamePlayed;if(i){var o,s;let e=((o=i.elapsedTimeSecs)==null?0:o)*1e3,t=((s=i.additionalTimeAddedSecs)==null?0:s)*1e3;p._reset(e,t)}a&&(a(n),a=null)}),{timer:{timeMs:()=>p.timeMs(),timeSecs:()=>p.timeSecs(),addedTimeMs:()=>p.addedTimeMs(),addedTimeSecs:()=>p.addedTimeSecs(),timeWithoutPenaltySecs:()=>p.timeWithoutPenaltySecs(),display:()=>p.display(),addPenalty:e=>p.addPenalty(e),isPaused:()=>p.isPaused(),isRunning:()=>p.isRunning()},gameReady:function(){var n=e.n(function*(){var e;if(i.sendMessage(`READY`,{}),c())return{puzzleString:c(),boardState:l(),theme:u(),completed:d(),readyData:r};let n=(e=t.timeout)==null?5e3:e;yield new Promise((e,t)=>{a=e,setTimeout(()=>{a&&(a=null,t(Error(`Timeout waiting for READY_DATA after ${n}ms`)))},n)});let o=c();if(!o)throw Error(`READY_DATA received but no puzzle data found`);return{puzzleString:o,boardState:l(),theme:u(),completed:d(),readyData:r}});return function(){return n.apply(this,arguments)}}(),gameLoaded:(e={})=>{i.sendMessage(`READY_GAME_LOADED`,{state:e,gameRuntimeContract:`1.0`,embedRuntimeContract:`1.0`})},on:(e,t)=>(f.has(e)||f.set(e,new Set),f.get(e).add(t),()=>{var n;(n=f.get(e))==null||n.delete(t)}),off:(e,t)=>{var n;(n=f.get(e))==null||n.delete(t)},updateGameState:(e,t)=>{var n,r;let a=s();a&&i.sendMessage(`UPLOAD_NEW_GAME_STATE`,{id:a,input:{boardState:e,elapsedTimeSecs:(n=t==null?void 0:t.elapsedTimeSecs)==null?p.timeWithoutPenaltySecs():n,additionalTimeAddedSecs:(r=t==null?void 0:t.additionalTimeAddedSecs)==null?p.addedTimeSecs():r,collabUserReferences:[]}})},gameCompleted:(t,n)=>{var r,a,o,c,l;p._conclude(),_();let u=e.t(e.t({},t),{},{elapsedTimeSecs:(r=t.elapsedTimeSecs)==null?p.timeWithoutPenaltySecs():r,additionalTimeAddedSecs:(a=t.additionalTimeAddedSecs)==null?p.addedTimeSecs():a}),d=(o=n==null?void 0:n.deeds)==null?[]:o;d.push({id:`points`,value:t.pointsAwarded}),d.push({id:`time`,value:Math.round((c=u.elapsedTimeSecs)==null?0:c)+Math.round((l=u.additionalTimeAddedSecs)==null?0:l)});let f=s();f&&i.sendMessage(`GAME_COMPLETED`,{id:f,input:u,config:n})},showCompletionScreen:(e,t,n=!0)=>{i.sendMessage(`SHOW_GAME_COMPLETE_SCREEN`,{results:e,showRetry:n,gameplay:t})},hitCheckpoint:(e,t,n)=>{var r;if(!s())return;let a=(r=l())==null?``:r,o={elapsedTimeSecs:p.timeWithoutPenaltySecs(),additionalTimeAddedSecs:p.addedTimeSecs()};i.sendMessage(`HIT_CHECKPOINT`,{checkpointName:e,gameplay:{inputStr:a,play:o},checkpointConfig:t,augConfig:n==null?{}:n})},_hostAPI:i}};var o=class extends Error{constructor(e,t,n){super(t),this.type=e,this.originalError=n,this.name=`EditorImportError`}};exports.EditorImportError=o,exports.createPuzzmoSDK=a;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./objectSpread2-C4RR_HMd.cjs`);function t(e){let t=e>=3600*1e3;return new Date(e).toISOString().slice(t?11:14,-1).split(`.`)[0]}function n(e=0,n=0){let r=e,i=n,a=0,o,s,c,l=()=>{var e;if(s===void 0)return r+i;if(o!==void 0)return o;let t=((e=c)==null?performance.now():e)-s-a;return r+i+t};return{_init:()=>{s===void 0&&(s=performance.now(),c=void 0)},_pause:()=>{c!==void 0||s===void 0||(c=performance.now())},_resume:()=>{c!==void 0&&(a+=performance.now()-c,c=void 0)},_reset:(e=0,t=0)=>{r=e,i=t,a=0,o=void 0,s=void 0,c=void 0},_conclude:()=>{if(c!==void 0){o=l();return}if(s===void 0){o=r+i;return}o=l()},timeMs:()=>l(),timeSecs:()=>l()/1e3,addedTimeMs:()=>i,addedTimeSecs:()=>i/1e3,timeWithoutPenaltySecs:()=>(l()-i)/1e3,addPenalty:e=>{i+=e},isPaused:()=>c!==void 0||s===void 0,isRunning:()=>s!==void 0&&c===void 0,display:()=>{let e=l()-i;return[t(Math.max(0,e)),i===0?``:t(i)]}}}function r(){let e=new Map;return typeof window<`u`&&window.addEventListener(`message`,t=>{var n;if(!(!(t==null||(n=t.data)==null)&&n.type))return;let r=t.data.type,i=e.get(r);if(i){var a,o;let e=(a=(o=t.data.data)==null?t.data.json:o)==null?{}:a;r!==`TIMER_TICK`&&r!==`TIMER_SYNC`&&console.log(`[Puzzmo SDK] received:`,r,e),i.forEach(t=>t(e))}}),{sendMessage:(e,t)=>{var n,r;let i={type:e,json:t,_:`p`,__:`mp`,private:!0};`parent`in window&&window.parent!==window&&window.parent.postMessage(i,`*`),window.postMessage(i,`*`),`webkit`in window&&!((n=window.webkit)==null||(n=n.messageHandlers)==null)&&n.app&&window.webkit.messageHandlers.app.postMessage(i),`puzzmoMessageString`in window&&window.puzzmoMessageString(JSON.stringify(i)),`ReactNativeWebView`in window&&(r=window.ReactNativeWebView)!=null&&r.postMessage&&window.ReactNativeWebView.postMessage(JSON.stringify(i)),e!==`TIMER_TICK`&&e!==`TIMER_SYNC`&&console.log(`[Puzzmo SDK] sent:`,e,t)},onMessage:(t,n)=>(e.has(t)||e.set(t,new Set),e.get(t).add(n),()=>{var r;(r=e.get(t))==null||r.delete(n)})}}var i=r();const a=(t={})=>{let r=null,a=null,o=()=>{var e;return r==null||(e=r.startOrFindGameplay)==null?void 0:e.gamePlayed},s=()=>{var e,t;return(e=(t=o())==null?void 0:t.id)==null?null:e},c=()=>{var e,t;return(e=(t=o())==null?void 0:t.puzzle.puzzle)==null?null:e},l=()=>{var e,t;return(e=(t=o())==null?void 0:t.boardState)==null?null:e},u=()=>{var e;return(e=r==null?void 0:r.theme)==null?null:e},d=()=>{var e,t;return(e=(t=o())==null?void 0:t.completed)==null?!1:e},f=new Map,p=n(),m=null,h=null,g=()=>{m||(m=setInterval(()=>{if(p.isPaused())return;let[e,t]=p.display();i.sendMessage(`TIMER_TICK`,{display:[e,t]})},500),h=setInterval(()=>{p.isPaused()||i.sendMessage(`TIMER_SYNC`,Math.floor(p.timeWithoutPenaltySecs()))},1e4))},_=()=>{m&&(clearInterval(m),m=null),h&&(clearInterval(h),h=null)},v=(e,t)=>{let n=f.get(e);n&&n.forEach(e=>e(t))};return i.onMessage(`START_GAME`,()=>{p._init(),g(),v(`start`)}),i.onMessage(`PAUSE_GAME`,()=>{p._pause(),v(`pause`)}),i.onMessage(`RESUME_GAME`,()=>{p._resume(),v(`resume`)}),i.onMessage(`SETTINGS_UPDATE`,e=>v(`settingsUpdate`,e)),i.onMessage(`KEYBOARD_KEY_PRESS`,e=>v(`keyboardKeyPress`,e)),i.onMessage(`KEYBOARD_CURSOR_CHANGE`,e=>v(`keyboardCursorChange`,e)),i.onMessage(`KEYBOARD_CURSOR_END`,()=>v(`keyboardCursorEnd`)),i.onMessage(`RETRY_PUZZLE`,()=>{p._reset(),_(),v(`retry`)}),i.onMessage(`READY_DATA`,e=>{var t;let n=e;r=n;let i=(t=n.startOrFindGameplay)==null?void 0:t.gamePlayed;if(i){var o,s;let e=((o=i.elapsedTimeSecs)==null?0:o)*1e3,t=((s=i.additionalTimeAddedSecs)==null?0:s)*1e3;p._reset(e,t)}a&&(a(n),a=null)}),{timer:{timeMs:()=>p.timeMs(),timeSecs:()=>p.timeSecs(),addedTimeMs:()=>p.addedTimeMs(),addedTimeSecs:()=>p.addedTimeSecs(),timeWithoutPenaltySecs:()=>p.timeWithoutPenaltySecs(),display:()=>p.display(),addPenalty:e=>p.addPenalty(e),isPaused:()=>p.isPaused(),isRunning:()=>p.isRunning()},gameReady:function(){var n=e.n(function*(){var e;if(i.sendMessage(`READY`,{}),c())return{puzzleString:c(),boardState:l(),theme:u(),completed:d(),readyData:r};let n=(e=t.timeout)==null?5e3:e;yield new Promise((e,t)=>{a=e,setTimeout(()=>{a&&(a=null,t(Error(`Timeout waiting for READY_DATA after ${n}ms`)))},n)});let o=c();if(!o)throw Error(`READY_DATA received but no puzzle data found`);return{puzzleString:o,boardState:l(),theme:u(),completed:d(),readyData:r}});return function(){return n.apply(this,arguments)}}(),gameLoaded:(e={})=>{i.sendMessage(`READY_GAME_LOADED`,{state:e,gameRuntimeContract:`1.0`,embedRuntimeContract:`1.0`})},on:(e,t)=>(f.has(e)||f.set(e,new Set),f.get(e).add(t),()=>{var n;(n=f.get(e))==null||n.delete(t)}),off:(e,t)=>{var n;(n=f.get(e))==null||n.delete(t)},updateGameState:(e,t)=>{var n,r;let a=s();a&&i.sendMessage(`UPLOAD_NEW_GAME_STATE`,{id:a,input:{boardState:e,elapsedTimeSecs:(n=t==null?void 0:t.elapsedTimeSecs)==null?p.timeWithoutPenaltySecs():n,additionalTimeAddedSecs:(r=t==null?void 0:t.additionalTimeAddedSecs)==null?p.addedTimeSecs():r,collabUserReferences:[]}})},gameCompleted:(t,n)=>{var r,a,o,c,l;p._conclude(),_();let u=e.t(e.t({},t),{},{elapsedTimeSecs:(r=t.elapsedTimeSecs)==null?p.timeWithoutPenaltySecs():r,additionalTimeAddedSecs:(a=t.additionalTimeAddedSecs)==null?p.addedTimeSecs():a}),d=(o=n==null?void 0:n.deeds)==null?[]:o;d.push({id:`points`,value:t.pointsAwarded}),d.push({id:`time`,value:Math.round((c=u.elapsedTimeSecs)==null?0:c)+Math.round((l=u.additionalTimeAddedSecs)==null?0:l)});let f=s();f&&i.sendMessage(`GAME_COMPLETED`,{id:f,input:u,config:n})},showCompletionScreen:(e,t,n=!0)=>{i.sendMessage(`SHOW_GAME_COMPLETE_SCREEN`,{results:e,showRetry:n,gameplay:t})},hitCheckpoint:(e,t,n)=>{var r;if(!s())return;let a=(r=l())==null?``:r,o={elapsedTimeSecs:p.timeWithoutPenaltySecs(),additionalTimeAddedSecs:p.addedTimeSecs()};i.sendMessage(`HIT_CHECKPOINT`,{checkpointName:e,gameplay:{inputStr:a,play:o},checkpointConfig:t,augConfig:n==null?{}:n})},keyboard:{show:e=>{i.sendMessage(`KEYBOARD_UPDATE_CONFIG`,e)},hide:()=>{i.sendMessage(`KEYBOARD_UPDATE_CONFIG`,{layout:[],symbols:{},highlight:[],disabled:[],xl:[],l:[],supportsDragCursor:!1})}},_hostAPI:i}},o={layout:[`qwertyuiop`,`asdfghjkl`,`↵zxcvbnm⌫`,void 0],symbols:{"↵":`Enter`,"⌫":`bsp`},highlight:[`↵`,`⌫`],disabled:[],xl:[],l:[`↵`,`⌫`],supportsDragCursor:!1};var s=class extends Error{constructor(e,t,n){super(t),this.type=e,this.originalError=n,this.name=`EditorImportError`}};exports.EditorImportError=s,exports.createPuzzmoSDK=a,exports.defaultKeyboardConfig=o;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/sdk.ts","../src/editor.ts"],"sourcesContent":["import type { MessagesSentFromEmbed, MessagesReceived, GamePlay, AugmentationConfig, CheckpointConfig, Theme, Deed } from \"./types\"\n\nexport type SDK = ReturnType<typeof createPuzzmoSDK>\n\nexport interface PuzzmoSDKOptions {\n /** Optional timeout in ms to wait for READY_DATA (default: 5000) */\n timeout?: number\n}\n\ntype SupportedOutgoingMessages = Pick<\n MessagesSentFromEmbed,\n | \"READY\"\n | \"READY_GAME_LOADED\"\n | \"GAME_COMPLETED\"\n | \"SHOW_GAME_COMPLETE_SCREEN\"\n | \"TIMER_TICK\"\n | \"TIMER_SYNC\"\n | \"UPLOAD_NEW_GAME_STATE\"\n | \"HIT_CHECKPOINT\"\n>\n\ntype SupportedIncomingMessages = Pick<\n MessagesReceived,\n \"READY_DATA\" | \"START_GAME\" | \"PAUSE_GAME\" | \"RESUME_GAME\" | \"SETTINGS_UPDATE\" | \"RETRY_PUZZLE\"\n>\n\ntype MessageHandler<T extends keyof SupportedIncomingMessages> = (data: SupportedIncomingMessages[T]) => void\n\nexport type SDKEventMap = {\n start: void\n pause: void\n resume: void\n retry: void\n settingsUpdate: any\n}\n\nexport type SDKEventType = keyof SDKEventMap\n\nexport interface SDKTimer {\n /** Get elapsed time in milliseconds */\n timeMs: () => number\n /** Get elapsed time in seconds */\n timeSecs: () => number\n /** Get added/penalty time in milliseconds */\n addedTimeMs: () => number\n /** Get added/penalty time in seconds */\n addedTimeSecs: () => number\n /** Get elapsed time without penalties in seconds */\n timeWithoutPenaltySecs: () => number\n /** Get formatted display strings [elapsed, added] */\n display: () => [string, string]\n /** Add penalty time in milliseconds */\n addPenalty: (ms: number) => void\n /** Check if timer is paused */\n isPaused: () => boolean\n /** Check if timer has been started */\n isRunning: () => boolean\n}\n\nfunction formatTime(timeMs: number): string {\n const isAnHourOrMore = timeMs >= 60 * 60 * 1000\n return new Date(timeMs)\n .toISOString()\n .slice(isAnHourOrMore ? 11 : 14, -1)\n .split(\".\")[0]\n}\n\nfunction createTimer(\n initialTimeMs = 0,\n initialAddedTimeMs = 0,\n): SDKTimer & {\n _init: () => void\n _pause: () => void\n _resume: () => void\n _reset: (initialTimeMs?: number, initialAddedTimeMs?: number) => void\n _conclude: () => void\n} {\n let baseTime = initialTimeMs\n let addedTime = initialAddedTimeMs\n let pausedTime = 0\n let concludeTime: number | undefined\n\n let startDate: number | undefined = undefined\n let pausedDate: number | undefined = undefined\n\n const getTime = (): number => {\n if (startDate === undefined) return baseTime + addedTime\n if (concludeTime !== undefined) return concludeTime\n const now = pausedDate ?? performance.now()\n const elapsed = now - startDate - pausedTime\n return baseTime + addedTime + elapsed\n }\n\n return {\n _init: () => {\n if (startDate === undefined) {\n startDate = performance.now()\n pausedDate = undefined\n }\n },\n _pause: () => {\n if (pausedDate !== undefined || startDate === undefined) return\n pausedDate = performance.now()\n },\n _resume: () => {\n if (pausedDate === undefined) return\n pausedTime += performance.now() - pausedDate\n pausedDate = undefined\n },\n _reset: (newInitialTimeMs = 0, newInitialAddedTimeMs = 0) => {\n baseTime = newInitialTimeMs\n addedTime = newInitialAddedTimeMs\n pausedTime = 0\n concludeTime = undefined\n startDate = undefined\n pausedDate = undefined\n },\n _conclude: () => {\n if (pausedDate !== undefined) {\n concludeTime = getTime()\n return\n }\n if (startDate === undefined) {\n concludeTime = baseTime + addedTime\n return\n }\n concludeTime = getTime()\n },\n timeMs: () => getTime(),\n timeSecs: () => getTime() / 1000,\n addedTimeMs: () => addedTime,\n addedTimeSecs: () => addedTime / 1000,\n timeWithoutPenaltySecs: () => (getTime() - addedTime) / 1000,\n addPenalty: (ms: number) => {\n addedTime += ms\n },\n isPaused: () => pausedDate !== undefined || startDate === undefined,\n isRunning: () => startDate !== undefined && pausedDate === undefined,\n display: () => {\n const elapsed = getTime() - addedTime\n const elapsedStr = formatTime(Math.max(0, elapsed))\n const addedStr = addedTime === 0 ? \"\" : formatTime(addedTime)\n return [elapsedStr, addedStr]\n },\n }\n}\n\nfunction createHostAPI() {\n const messageHandlers = new Map<string, Set<(data: any) => void>>()\n\n const sendMessage = <T extends keyof SupportedOutgoingMessages>(type: T, json: SupportedOutgoingMessages[T]) => {\n const message = { type, json, _: \"p\", __: \"mp\", private: true }\n\n if (\"parent\" in window && window.parent !== window) window.parent.postMessage(message, \"*\")\n\n window.postMessage(message, \"*\")\n\n if (\"webkit\" in window && (window as any).webkit?.messageHandlers?.app) (window as any).webkit.messageHandlers.app.postMessage(message)\n\n if (\"puzzmoMessageString\" in window) (window as any).puzzmoMessageString(JSON.stringify(message))\n\n if (\"ReactNativeWebView\" in window && (window as any).ReactNativeWebView?.postMessage)\n (window as any).ReactNativeWebView.postMessage(JSON.stringify(message))\n\n if (type !== \"TIMER_TICK\" && type !== \"TIMER_SYNC\") console.log(\"[Puzzmo SDK] sent:\", type, json)\n }\n\n const onMessage = <T extends keyof SupportedIncomingMessages>(type: T, handler: MessageHandler<T>) => {\n if (!messageHandlers.has(type)) messageHandlers.set(type, new Set())\n messageHandlers.get(type)!.add(handler)\n\n return () => {\n messageHandlers.get(type)?.delete(handler)\n }\n }\n\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"message\", (event) => {\n if (!event?.data?.type) return\n const msgType = event.data.type as string\n const handlers = messageHandlers.get(msgType)\n if (handlers) {\n const msgData = event.data.data ?? event.data.json ?? {}\n if (msgType !== \"TIMER_TICK\" && msgType !== \"TIMER_SYNC\") console.log(\"[Puzzmo SDK] received:\", msgType, msgData)\n handlers.forEach((handler) => handler(msgData))\n }\n })\n }\n\n return { sendMessage, onMessage }\n}\n\nconst hostAPI = createHostAPI()\n\n/** Creates a Puzzmo SDK instance for communicating with the Puzzmo host */\nexport const createPuzzmoSDK = (options: PuzzmoSDKOptions = {}) => {\n let readyData: MessagesReceived[\"READY_DATA\"] | null = null\n let readyDataResolve: ((data: MessagesReceived[\"READY_DATA\"]) => void) | null = null\n\n const getGameplay = () => readyData?.startOrFindGameplay?.gamePlayed\n const getGameplayID = () => getGameplay()?.id ?? null\n const getPuzzleString = () => getGameplay()?.puzzle.puzzle ?? null\n const getBoardState = () => getGameplay()?.boardState ?? null\n const getTheme = () => readyData?.theme ?? null\n const getCompleted = () => getGameplay()?.completed ?? false\n\n const eventListeners = new Map<SDKEventType, Set<(data?: any) => void>>()\n\n const internalTimer = createTimer()\n let timerTickInterval: ReturnType<typeof setInterval> | null = null\n let timerSyncInterval: ReturnType<typeof setInterval> | null = null\n\n const startTimerIntervals = () => {\n if (timerTickInterval) return\n\n timerTickInterval = setInterval(() => {\n if (internalTimer.isPaused()) return\n const [elapsed, added] = internalTimer.display()\n hostAPI.sendMessage(\"TIMER_TICK\", { display: [elapsed, added] })\n }, 500)\n\n timerSyncInterval = setInterval(() => {\n if (internalTimer.isPaused()) return\n hostAPI.sendMessage(\"TIMER_SYNC\", Math.floor(internalTimer.timeWithoutPenaltySecs()))\n }, 10000)\n }\n\n const stopTimerIntervals = () => {\n if (timerTickInterval) {\n clearInterval(timerTickInterval)\n timerTickInterval = null\n }\n if (timerSyncInterval) {\n clearInterval(timerSyncInterval)\n timerSyncInterval = null\n }\n }\n\n const emit = <T extends SDKEventType>(event: T, data?: SDKEventMap[T]) => {\n const listeners = eventListeners.get(event)\n if (listeners) listeners.forEach((listener) => listener(data))\n }\n\n hostAPI.onMessage(\"START_GAME\", () => {\n internalTimer._init()\n startTimerIntervals()\n emit(\"start\")\n })\n\n hostAPI.onMessage(\"PAUSE_GAME\", () => {\n internalTimer._pause()\n emit(\"pause\")\n })\n\n hostAPI.onMessage(\"RESUME_GAME\", () => {\n internalTimer._resume()\n emit(\"resume\")\n })\n\n hostAPI.onMessage(\"SETTINGS_UPDATE\", (data) => emit(\"settingsUpdate\", data))\n\n hostAPI.onMessage(\"RETRY_PUZZLE\", () => {\n internalTimer._reset()\n stopTimerIntervals()\n emit(\"retry\")\n })\n\n hostAPI.onMessage(\"READY_DATA\", (data) => {\n const bootstrapData = data as MessagesReceived[\"READY_DATA\"]\n readyData = bootstrapData\n\n const gamePlayed = bootstrapData.startOrFindGameplay?.gamePlayed\n if (gamePlayed) {\n const existingTime = (gamePlayed.elapsedTimeSecs ?? 0) * 1000\n const existingAddedTime = (gamePlayed.additionalTimeAddedSecs ?? 0) * 1000\n internalTimer._reset(existingTime, existingAddedTime)\n }\n\n if (readyDataResolve) {\n readyDataResolve(bootstrapData)\n readyDataResolve = null\n }\n })\n\n const timer: SDKTimer = {\n timeMs: () => internalTimer.timeMs(),\n timeSecs: () => internalTimer.timeSecs(),\n addedTimeMs: () => internalTimer.addedTimeMs(),\n addedTimeSecs: () => internalTimer.addedTimeSecs(),\n timeWithoutPenaltySecs: () => internalTimer.timeWithoutPenaltySecs(),\n display: () => internalTimer.display(),\n addPenalty: (ms: number) => internalTimer.addPenalty(ms),\n isPaused: () => internalTimer.isPaused(),\n isRunning: () => internalTimer.isRunning(),\n }\n\n return {\n timer,\n\n gameReady: async (): Promise<{\n puzzleString: string\n boardState: string | null\n theme: Theme | null\n completed: boolean\n readyData: MessagesReceived[\"READY_DATA\"] | null\n }> => {\n hostAPI.sendMessage(\"READY\", {})\n\n if (getPuzzleString()) {\n return {\n puzzleString: getPuzzleString()!,\n boardState: getBoardState(),\n theme: getTheme(),\n completed: getCompleted(),\n readyData,\n }\n }\n\n const timeout = options.timeout ?? 5000\n const readyDataPromise = new Promise<MessagesReceived[\"READY_DATA\"]>((resolve, reject) => {\n readyDataResolve = resolve\n setTimeout(() => {\n if (readyDataResolve) {\n readyDataResolve = null\n reject(new Error(`Timeout waiting for READY_DATA after ${timeout}ms`))\n }\n }, timeout)\n })\n\n await readyDataPromise\n\n const puzzleString = getPuzzleString()\n if (!puzzleString) throw new Error(\"READY_DATA received but no puzzle data found\")\n\n return {\n puzzleString,\n boardState: getBoardState(),\n theme: getTheme(),\n completed: getCompleted(),\n readyData,\n }\n },\n\n gameLoaded: (state: any = {}) => {\n hostAPI.sendMessage(\"READY_GAME_LOADED\", {\n state,\n gameRuntimeContract: \"1.0\",\n embedRuntimeContract: \"1.0\",\n })\n },\n\n on: <T extends SDKEventType>(event: T, listener: (data?: SDKEventMap[T]) => void): (() => void) => {\n if (!eventListeners.has(event)) eventListeners.set(event, new Set())\n eventListeners.get(event)!.add(listener)\n return () => {\n eventListeners.get(event)?.delete(listener)\n }\n },\n\n off: <T extends SDKEventType>(event: T, listener: (data?: SDKEventMap[T]) => void) => {\n eventListeners.get(event)?.delete(listener)\n },\n\n updateGameState: (inputString: string, play?: Partial<GamePlay>) => {\n const gameplayID = getGameplayID()\n if (!gameplayID) return\n\n hostAPI.sendMessage(\"UPLOAD_NEW_GAME_STATE\", {\n id: gameplayID,\n input: {\n boardState: inputString,\n elapsedTimeSecs: play?.elapsedTimeSecs ?? internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: play?.additionalTimeAddedSecs ?? internalTimer.addedTimeSecs(),\n collabUserReferences: [],\n },\n })\n },\n\n gameCompleted: (play: Partial<GamePlay>, config?: AugmentationConfig) => {\n internalTimer._conclude()\n stopTimerIntervals()\n\n const finalPlay: Partial<GamePlay> = {\n ...play,\n elapsedTimeSecs: play.elapsedTimeSecs ?? internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: play.additionalTimeAddedSecs ?? internalTimer.addedTimeSecs(),\n }\n\n const deeds: Deed[] = (config?.deeds as any) ?? []\n deeds.push({ id: \"points\", value: play.pointsAwarded })\n deeds.push({\n id: \"time\",\n value: Math.round(finalPlay.elapsedTimeSecs ?? 0) + Math.round(finalPlay.additionalTimeAddedSecs ?? 0),\n })\n\n const gameplayID = getGameplayID()\n if (gameplayID) {\n hostAPI.sendMessage(\"GAME_COMPLETED\", {\n id: gameplayID,\n input: finalPlay,\n config,\n })\n }\n },\n\n showCompletionScreen: (results: any[], gameplay: GamePlay, showRetry = true) => {\n hostAPI.sendMessage(\"SHOW_GAME_COMPLETE_SCREEN\", {\n results,\n showRetry,\n gameplay,\n })\n },\n\n hitCheckpoint: (checkpointName: string, checkpointConfig: CheckpointConfig, config?: AugmentationConfig) => {\n const gameplayID = getGameplayID()\n if (!gameplayID) return\n\n const inputStr = getBoardState() ?? \"\"\n const play: Partial<GamePlay> = {\n elapsedTimeSecs: internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: internalTimer.addedTimeSecs(),\n }\n\n hostAPI.sendMessage(\"HIT_CHECKPOINT\", {\n checkpointName,\n gameplay: { inputStr, play },\n checkpointConfig,\n augConfig: config ?? {},\n })\n },\n\n _hostAPI: hostAPI,\n }\n}\n","/** Severity level for validation issues */\nexport type ValidationLevel = \"error\" | \"warning\" | \"info\"\n\n/** Represents a single validation issue found during puzzle validation */\nexport interface ValidationIssue {\n level: ValidationLevel\n message: string\n line?: number\n col?: number\n length?: number\n}\n\n/** Complete validation report for a puzzle */\nexport interface ValidationReport {\n success: boolean\n issues: ValidationIssue[]\n}\n\nexport type ImportErrorType = \"invalid_format\" | \"parsing_error\" | \"unknown\"\n\n/** Custom error class for workshop import failures */\nexport class EditorImportError extends Error {\n constructor(\n public type: ImportErrorType,\n message: string,\n public originalError?: unknown,\n ) {\n super(message)\n this.name = \"EditorImportError\"\n }\n}\n\n/** Result of a successful puzzle import operation */\nexport interface ImportResult {\n data: string\n warnings?: ValidationIssue[]\n title?: string\n authors?: string[]\n editors?: string[]\n}\n\n/** Settings UI descriptor returned by an editor bundle */\nexport interface EditorBundleSettings<TComponent = unknown> {\n components: TComponent[]\n defaults: Record<string, unknown>\n}\n\n/** Main interface for a Workshop bundle */\nexport interface EditorBundle<TSettingsComponent = unknown> {\n validator: {\n validate(data: string): Promise<ValidationReport> | ValidationReport\n }\n importer?: {\n onImport(filename: string, contents: string | ArrayBuffer): Promise<ImportResult> | ImportResult\n }\n /** Embed-level settings UI, populated from the bundle's declared settings */\n settings?: EditorBundleSettings<TSettingsComponent>\n /** Editor-level settings UI, populated from the bundle's declared editor settings */\n editorSettings?: EditorBundleSettings<TSettingsComponent>\n /** Custom puzzle editor, if provided by the bundle */\n editor?: {\n mount(...args: unknown[]): unknown\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/sdk.ts","../src/keyboard.ts","../src/editor.ts"],"sourcesContent":["import type {\n MessagesSentFromEmbed,\n MessagesReceived,\n GamePlay,\n AugmentationConfig,\n CheckpointConfig,\n Theme,\n Deed,\n KeyboardConfig,\n} from \"./types\"\n\nexport type SDK = ReturnType<typeof createPuzzmoSDK>\n\nexport interface PuzzmoSDKOptions {\n /** Optional timeout in ms to wait for READY_DATA (default: 5000) */\n timeout?: number\n}\n\ntype SupportedOutgoingMessages = Pick<\n MessagesSentFromEmbed,\n | \"READY\"\n | \"READY_GAME_LOADED\"\n | \"GAME_COMPLETED\"\n | \"SHOW_GAME_COMPLETE_SCREEN\"\n | \"TIMER_TICK\"\n | \"TIMER_SYNC\"\n | \"UPLOAD_NEW_GAME_STATE\"\n | \"HIT_CHECKPOINT\"\n | \"KEYBOARD_UPDATE_CONFIG\"\n>\n\ntype SupportedIncomingMessages = Pick<\n MessagesReceived,\n | \"READY_DATA\"\n | \"START_GAME\"\n | \"PAUSE_GAME\"\n | \"RESUME_GAME\"\n | \"SETTINGS_UPDATE\"\n | \"RETRY_PUZZLE\"\n | \"KEYBOARD_KEY_PRESS\"\n | \"KEYBOARD_CURSOR_CHANGE\"\n | \"KEYBOARD_CURSOR_END\"\n>\n\ntype MessageHandler<T extends keyof SupportedIncomingMessages> = (data: SupportedIncomingMessages[T]) => void\n\nexport type SDKEventMap = {\n start: void\n pause: void\n resume: void\n retry: void\n settingsUpdate: any\n /** A key on the on-screen keyboard was tapped. */\n keyboardKeyPress: { key: string }\n /** The drag cursor moved across the keyboard. Only fires when `supportsDragCursor` is true. */\n keyboardCursorChange: { position: [number, number] }\n /** The drag cursor was released. Only fires when `supportsDragCursor` is true. */\n keyboardCursorEnd: void\n}\n\nexport type SDKEventType = keyof SDKEventMap\n\nexport interface SDKTimer {\n /** Get elapsed time in milliseconds */\n timeMs: () => number\n /** Get elapsed time in seconds */\n timeSecs: () => number\n /** Get added/penalty time in milliseconds */\n addedTimeMs: () => number\n /** Get added/penalty time in seconds */\n addedTimeSecs: () => number\n /** Get elapsed time without penalties in seconds */\n timeWithoutPenaltySecs: () => number\n /** Get formatted display strings [elapsed, added] */\n display: () => [string, string]\n /** Add penalty time in milliseconds */\n addPenalty: (ms: number) => void\n /** Check if timer is paused */\n isPaused: () => boolean\n /** Check if timer has been started */\n isRunning: () => boolean\n}\n\nfunction formatTime(timeMs: number): string {\n const isAnHourOrMore = timeMs >= 60 * 60 * 1000\n return new Date(timeMs)\n .toISOString()\n .slice(isAnHourOrMore ? 11 : 14, -1)\n .split(\".\")[0]\n}\n\nfunction createTimer(\n initialTimeMs = 0,\n initialAddedTimeMs = 0,\n): SDKTimer & {\n _init: () => void\n _pause: () => void\n _resume: () => void\n _reset: (initialTimeMs?: number, initialAddedTimeMs?: number) => void\n _conclude: () => void\n} {\n let baseTime = initialTimeMs\n let addedTime = initialAddedTimeMs\n let pausedTime = 0\n let concludeTime: number | undefined\n\n let startDate: number | undefined = undefined\n let pausedDate: number | undefined = undefined\n\n const getTime = (): number => {\n if (startDate === undefined) return baseTime + addedTime\n if (concludeTime !== undefined) return concludeTime\n const now = pausedDate ?? performance.now()\n const elapsed = now - startDate - pausedTime\n return baseTime + addedTime + elapsed\n }\n\n return {\n _init: () => {\n if (startDate === undefined) {\n startDate = performance.now()\n pausedDate = undefined\n }\n },\n _pause: () => {\n if (pausedDate !== undefined || startDate === undefined) return\n pausedDate = performance.now()\n },\n _resume: () => {\n if (pausedDate === undefined) return\n pausedTime += performance.now() - pausedDate\n pausedDate = undefined\n },\n _reset: (newInitialTimeMs = 0, newInitialAddedTimeMs = 0) => {\n baseTime = newInitialTimeMs\n addedTime = newInitialAddedTimeMs\n pausedTime = 0\n concludeTime = undefined\n startDate = undefined\n pausedDate = undefined\n },\n _conclude: () => {\n if (pausedDate !== undefined) {\n concludeTime = getTime()\n return\n }\n if (startDate === undefined) {\n concludeTime = baseTime + addedTime\n return\n }\n concludeTime = getTime()\n },\n timeMs: () => getTime(),\n timeSecs: () => getTime() / 1000,\n addedTimeMs: () => addedTime,\n addedTimeSecs: () => addedTime / 1000,\n timeWithoutPenaltySecs: () => (getTime() - addedTime) / 1000,\n addPenalty: (ms: number) => {\n addedTime += ms\n },\n isPaused: () => pausedDate !== undefined || startDate === undefined,\n isRunning: () => startDate !== undefined && pausedDate === undefined,\n display: () => {\n const elapsed = getTime() - addedTime\n const elapsedStr = formatTime(Math.max(0, elapsed))\n const addedStr = addedTime === 0 ? \"\" : formatTime(addedTime)\n return [elapsedStr, addedStr]\n },\n }\n}\n\nfunction createHostAPI() {\n const messageHandlers = new Map<string, Set<(data: any) => void>>()\n\n const sendMessage = <T extends keyof SupportedOutgoingMessages>(type: T, json: SupportedOutgoingMessages[T]) => {\n const message = { type, json, _: \"p\", __: \"mp\", private: true }\n\n if (\"parent\" in window && window.parent !== window) window.parent.postMessage(message, \"*\")\n\n window.postMessage(message, \"*\")\n\n if (\"webkit\" in window && (window as any).webkit?.messageHandlers?.app) (window as any).webkit.messageHandlers.app.postMessage(message)\n\n if (\"puzzmoMessageString\" in window) (window as any).puzzmoMessageString(JSON.stringify(message))\n\n if (\"ReactNativeWebView\" in window && (window as any).ReactNativeWebView?.postMessage)\n (window as any).ReactNativeWebView.postMessage(JSON.stringify(message))\n\n if (type !== \"TIMER_TICK\" && type !== \"TIMER_SYNC\") console.log(\"[Puzzmo SDK] sent:\", type, json)\n }\n\n const onMessage = <T extends keyof SupportedIncomingMessages>(type: T, handler: MessageHandler<T>) => {\n if (!messageHandlers.has(type)) messageHandlers.set(type, new Set())\n messageHandlers.get(type)!.add(handler)\n\n return () => {\n messageHandlers.get(type)?.delete(handler)\n }\n }\n\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"message\", (event) => {\n if (!event?.data?.type) return\n const msgType = event.data.type as string\n const handlers = messageHandlers.get(msgType)\n if (handlers) {\n const msgData = event.data.data ?? event.data.json ?? {}\n if (msgType !== \"TIMER_TICK\" && msgType !== \"TIMER_SYNC\") console.log(\"[Puzzmo SDK] received:\", msgType, msgData)\n handlers.forEach((handler) => handler(msgData))\n }\n })\n }\n\n return { sendMessage, onMessage }\n}\n\nconst hostAPI = createHostAPI()\n\n/** Creates a Puzzmo SDK instance for communicating with the Puzzmo host */\nexport const createPuzzmoSDK = (options: PuzzmoSDKOptions = {}) => {\n let readyData: MessagesReceived[\"READY_DATA\"] | null = null\n let readyDataResolve: ((data: MessagesReceived[\"READY_DATA\"]) => void) | null = null\n\n const getGameplay = () => readyData?.startOrFindGameplay?.gamePlayed\n const getGameplayID = () => getGameplay()?.id ?? null\n const getPuzzleString = () => getGameplay()?.puzzle.puzzle ?? null\n const getBoardState = () => getGameplay()?.boardState ?? null\n const getTheme = () => readyData?.theme ?? null\n const getCompleted = () => getGameplay()?.completed ?? false\n\n const eventListeners = new Map<SDKEventType, Set<(data?: any) => void>>()\n\n const internalTimer = createTimer()\n let timerTickInterval: ReturnType<typeof setInterval> | null = null\n let timerSyncInterval: ReturnType<typeof setInterval> | null = null\n\n const startTimerIntervals = () => {\n if (timerTickInterval) return\n\n timerTickInterval = setInterval(() => {\n if (internalTimer.isPaused()) return\n const [elapsed, added] = internalTimer.display()\n hostAPI.sendMessage(\"TIMER_TICK\", { display: [elapsed, added] })\n }, 500)\n\n timerSyncInterval = setInterval(() => {\n if (internalTimer.isPaused()) return\n hostAPI.sendMessage(\"TIMER_SYNC\", Math.floor(internalTimer.timeWithoutPenaltySecs()))\n }, 10000)\n }\n\n const stopTimerIntervals = () => {\n if (timerTickInterval) {\n clearInterval(timerTickInterval)\n timerTickInterval = null\n }\n if (timerSyncInterval) {\n clearInterval(timerSyncInterval)\n timerSyncInterval = null\n }\n }\n\n const emit = <T extends SDKEventType>(event: T, data?: SDKEventMap[T]) => {\n const listeners = eventListeners.get(event)\n if (listeners) listeners.forEach((listener) => listener(data))\n }\n\n hostAPI.onMessage(\"START_GAME\", () => {\n internalTimer._init()\n startTimerIntervals()\n emit(\"start\")\n })\n\n hostAPI.onMessage(\"PAUSE_GAME\", () => {\n internalTimer._pause()\n emit(\"pause\")\n })\n\n hostAPI.onMessage(\"RESUME_GAME\", () => {\n internalTimer._resume()\n emit(\"resume\")\n })\n\n hostAPI.onMessage(\"SETTINGS_UPDATE\", (data) => emit(\"settingsUpdate\", data))\n\n hostAPI.onMessage(\"KEYBOARD_KEY_PRESS\", (data) => emit(\"keyboardKeyPress\", data))\n hostAPI.onMessage(\"KEYBOARD_CURSOR_CHANGE\", (data) => emit(\"keyboardCursorChange\", data))\n hostAPI.onMessage(\"KEYBOARD_CURSOR_END\", () => emit(\"keyboardCursorEnd\"))\n\n hostAPI.onMessage(\"RETRY_PUZZLE\", () => {\n internalTimer._reset()\n stopTimerIntervals()\n emit(\"retry\")\n })\n\n hostAPI.onMessage(\"READY_DATA\", (data) => {\n const bootstrapData = data as MessagesReceived[\"READY_DATA\"]\n readyData = bootstrapData\n\n const gamePlayed = bootstrapData.startOrFindGameplay?.gamePlayed\n if (gamePlayed) {\n const existingTime = (gamePlayed.elapsedTimeSecs ?? 0) * 1000\n const existingAddedTime = (gamePlayed.additionalTimeAddedSecs ?? 0) * 1000\n internalTimer._reset(existingTime, existingAddedTime)\n }\n\n if (readyDataResolve) {\n readyDataResolve(bootstrapData)\n readyDataResolve = null\n }\n })\n\n const timer: SDKTimer = {\n timeMs: () => internalTimer.timeMs(),\n timeSecs: () => internalTimer.timeSecs(),\n addedTimeMs: () => internalTimer.addedTimeMs(),\n addedTimeSecs: () => internalTimer.addedTimeSecs(),\n timeWithoutPenaltySecs: () => internalTimer.timeWithoutPenaltySecs(),\n display: () => internalTimer.display(),\n addPenalty: (ms: number) => internalTimer.addPenalty(ms),\n isPaused: () => internalTimer.isPaused(),\n isRunning: () => internalTimer.isRunning(),\n }\n\n return {\n timer,\n\n gameReady: async (): Promise<{\n puzzleString: string\n boardState: string | null\n theme: Theme | null\n completed: boolean\n readyData: MessagesReceived[\"READY_DATA\"] | null\n }> => {\n hostAPI.sendMessage(\"READY\", {})\n\n if (getPuzzleString()) {\n return {\n puzzleString: getPuzzleString()!,\n boardState: getBoardState(),\n theme: getTheme(),\n completed: getCompleted(),\n readyData,\n }\n }\n\n const timeout = options.timeout ?? 5000\n const readyDataPromise = new Promise<MessagesReceived[\"READY_DATA\"]>((resolve, reject) => {\n readyDataResolve = resolve\n setTimeout(() => {\n if (readyDataResolve) {\n readyDataResolve = null\n reject(new Error(`Timeout waiting for READY_DATA after ${timeout}ms`))\n }\n }, timeout)\n })\n\n await readyDataPromise\n\n const puzzleString = getPuzzleString()\n if (!puzzleString) throw new Error(\"READY_DATA received but no puzzle data found\")\n\n return {\n puzzleString,\n boardState: getBoardState(),\n theme: getTheme(),\n completed: getCompleted(),\n readyData,\n }\n },\n\n gameLoaded: (state: any = {}) => {\n hostAPI.sendMessage(\"READY_GAME_LOADED\", {\n state,\n gameRuntimeContract: \"1.0\",\n embedRuntimeContract: \"1.0\",\n })\n },\n\n on: <T extends SDKEventType>(event: T, listener: (data?: SDKEventMap[T]) => void): (() => void) => {\n if (!eventListeners.has(event)) eventListeners.set(event, new Set())\n eventListeners.get(event)!.add(listener)\n return () => {\n eventListeners.get(event)?.delete(listener)\n }\n },\n\n off: <T extends SDKEventType>(event: T, listener: (data?: SDKEventMap[T]) => void) => {\n eventListeners.get(event)?.delete(listener)\n },\n\n updateGameState: (inputString: string, play?: Partial<GamePlay>) => {\n const gameplayID = getGameplayID()\n if (!gameplayID) return\n\n hostAPI.sendMessage(\"UPLOAD_NEW_GAME_STATE\", {\n id: gameplayID,\n input: {\n boardState: inputString,\n elapsedTimeSecs: play?.elapsedTimeSecs ?? internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: play?.additionalTimeAddedSecs ?? internalTimer.addedTimeSecs(),\n collabUserReferences: [],\n },\n })\n },\n\n gameCompleted: (play: Partial<GamePlay>, config?: AugmentationConfig) => {\n internalTimer._conclude()\n stopTimerIntervals()\n\n const finalPlay: Partial<GamePlay> = {\n ...play,\n elapsedTimeSecs: play.elapsedTimeSecs ?? internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: play.additionalTimeAddedSecs ?? internalTimer.addedTimeSecs(),\n }\n\n const deeds: Deed[] = (config?.deeds as any) ?? []\n deeds.push({ id: \"points\", value: play.pointsAwarded })\n deeds.push({\n id: \"time\",\n value: Math.round(finalPlay.elapsedTimeSecs ?? 0) + Math.round(finalPlay.additionalTimeAddedSecs ?? 0),\n })\n\n const gameplayID = getGameplayID()\n if (gameplayID) {\n hostAPI.sendMessage(\"GAME_COMPLETED\", {\n id: gameplayID,\n input: finalPlay,\n config,\n })\n }\n },\n\n showCompletionScreen: (results: any[], gameplay: GamePlay, showRetry = true) => {\n hostAPI.sendMessage(\"SHOW_GAME_COMPLETE_SCREEN\", {\n results,\n showRetry,\n gameplay,\n })\n },\n\n hitCheckpoint: (checkpointName: string, checkpointConfig: CheckpointConfig, config?: AugmentationConfig) => {\n const gameplayID = getGameplayID()\n if (!gameplayID) return\n\n const inputStr = getBoardState() ?? \"\"\n const play: Partial<GamePlay> = {\n elapsedTimeSecs: internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: internalTimer.addedTimeSecs(),\n }\n\n hostAPI.sendMessage(\"HIT_CHECKPOINT\", {\n checkpointName,\n gameplay: { inputStr, play },\n checkpointConfig,\n augConfig: config ?? {},\n })\n },\n\n keyboard: {\n /** Show the on-screen keyboard with the given config. Call again to update state (e.g. to change disabled keys). */\n show: (config: KeyboardConfig) => {\n hostAPI.sendMessage(\"KEYBOARD_UPDATE_CONFIG\", config)\n },\n /** Hide the on-screen keyboard. */\n hide: () => {\n hostAPI.sendMessage(\"KEYBOARD_UPDATE_CONFIG\", {\n layout: [],\n symbols: {},\n highlight: [],\n disabled: [],\n xl: [],\n l: [],\n supportsDragCursor: false,\n })\n },\n },\n\n _hostAPI: hostAPI,\n }\n}\n","import type { KeyboardConfig } from \"./types\"\n\n/**\n * A standard QWERTY layout with Enter and Backspace — a reasonable default for\n * any game that needs text input. Customize from here by spreading and overriding.\n *\n * @example\n * // Use as-is\n * sdk.keyboard.show(defaultKeyboardConfig)\n *\n * @example\n * // Extend with dynamic disabled letters\n * sdk.keyboard.show({ ...defaultKeyboardConfig, disabled: usedLetters })\n */\nexport const defaultKeyboardConfig: KeyboardConfig = {\n layout: [\"qwertyuiop\", \"asdfghjkl\", \"↵zxcvbnm⌫\", undefined],\n symbols: { \"↵\": \"Enter\", \"⌫\": \"bsp\" },\n highlight: [\"↵\", \"⌫\"],\n disabled: [],\n xl: [],\n l: [\"↵\", \"⌫\"],\n supportsDragCursor: false,\n}\n","/** Severity level for validation issues */\nexport type ValidationLevel = \"error\" | \"warning\" | \"info\"\n\n/** Represents a single validation issue found during puzzle validation */\nexport interface ValidationIssue {\n level: ValidationLevel\n message: string\n line?: number\n col?: number\n length?: number\n}\n\n/** Complete validation report for a puzzle */\nexport interface ValidationReport {\n success: boolean\n issues: ValidationIssue[]\n}\n\nexport type ImportErrorType = \"invalid_format\" | \"parsing_error\" | \"unknown\"\n\n/** Custom error class for workshop import failures */\nexport class EditorImportError extends Error {\n constructor(\n public type: ImportErrorType,\n message: string,\n public originalError?: unknown,\n ) {\n super(message)\n this.name = \"EditorImportError\"\n }\n}\n\n/** Result of a successful puzzle import operation */\nexport interface ImportResult {\n data: string\n warnings?: ValidationIssue[]\n title?: string\n authors?: string[]\n editors?: string[]\n}\n\n/** Settings UI descriptor returned by an editor bundle */\nexport interface EditorBundleSettings<TComponent = unknown> {\n components: TComponent[]\n defaults: Record<string, unknown>\n}\n\n/** Main interface for a Workshop bundle */\nexport interface EditorBundle<TSettingsComponent = unknown> {\n validator: {\n validate(data: string): Promise<ValidationReport> | ValidationReport\n }\n importer?: {\n onImport(filename: string, contents: string | ArrayBuffer): Promise<ImportResult> | ImportResult\n }\n /** Embed-level settings UI, populated from the bundle's declared settings */\n settings?: EditorBundleSettings<TSettingsComponent>\n /** Editor-level settings UI, populated from the bundle's declared editor settings */\n editorSettings?: EditorBundleSettings<TSettingsComponent>\n /** Custom puzzle editor, if provided by the bundle */\n editor?: {\n mount(...args: unknown[]): unknown\n }\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { createPuzzmoSDK } from "./sdk";
2
+ export { defaultKeyboardConfig } from "./keyboard";
2
3
  export type { SDK as PuzzmoSDK, PuzzmoSDKOptions, SDKEventMap, SDKEventType, SDKTimer } from "./sdk";
3
- export type { Theme, GamePlay, AugmentationConfig, CheckpointConfig, Deed, GameOverMessageUIComponent, BootstrapGameData, MessagesReceived, MessagesSentFromEmbed, ThumbnailConfig, } from "./types";
4
+ export type { Theme, GamePlay, AugmentationConfig, CheckpointConfig, Deed, GameOverMessageUIComponent, BootstrapGameData, MessagesReceived, MessagesSentFromEmbed, ThumbnailConfig, KeyboardConfig, } from "./types";
4
5
  export type { ValidationIssue, ValidationReport, ImportErrorType, ImportResult, EditorBundle } from "./editor";
5
6
  export { EditorImportError } from "./editor";
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,OAAO,CAAA;AAEvC,YAAY,EAAE,GAAG,IAAI,SAAS,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEpG,YAAY,EACV,KAAK,EACL,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EAChB,IAAI,EACJ,0BAA0B,EAC1B,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,GAChB,MAAM,SAAS,CAAA;AAEhB,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE9G,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,OAAO,CAAA;AACvC,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAElD,YAAY,EAAE,GAAG,IAAI,SAAS,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEpG,YAAY,EACV,KAAK,EACL,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EAChB,IAAI,EACJ,0BAA0B,EAC1B,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,cAAc,GACf,MAAM,SAAS,CAAA;AAEhB,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE9G,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA"}
package/dist/index.js CHANGED
@@ -121,7 +121,7 @@ const o = (n = {}) => {
121
121
  m._pause(), y("pause");
122
122
  }), a.onMessage("RESUME_GAME", () => {
123
123
  m._resume(), y("resume");
124
- }), a.onMessage("SETTINGS_UPDATE", (e) => y("settingsUpdate", e)), a.onMessage("RETRY_PUZZLE", () => {
124
+ }), a.onMessage("SETTINGS_UPDATE", (e) => y("settingsUpdate", e)), a.onMessage("KEYBOARD_KEY_PRESS", (e) => y("keyboardKeyPress", e)), a.onMessage("KEYBOARD_CURSOR_CHANGE", (e) => y("keyboardCursorChange", e)), a.onMessage("KEYBOARD_CURSOR_END", () => y("keyboardCursorEnd")), a.onMessage("RETRY_PUZZLE", () => {
125
125
  m._reset(), v(), y("retry");
126
126
  }), a.onMessage("READY_DATA", (e) => {
127
127
  var t;
@@ -249,15 +249,47 @@ const o = (n = {}) => {
249
249
  augConfig: n == null ? {} : n
250
250
  });
251
251
  },
252
+ keyboard: {
253
+ show: (e) => {
254
+ a.sendMessage("KEYBOARD_UPDATE_CONFIG", e);
255
+ },
256
+ hide: () => {
257
+ a.sendMessage("KEYBOARD_UPDATE_CONFIG", {
258
+ layout: [],
259
+ symbols: {},
260
+ highlight: [],
261
+ disabled: [],
262
+ xl: [],
263
+ l: [],
264
+ supportsDragCursor: !1
265
+ });
266
+ }
267
+ },
252
268
  _hostAPI: a
253
269
  };
270
+ }, s = {
271
+ layout: [
272
+ "qwertyuiop",
273
+ "asdfghjkl",
274
+ "↵zxcvbnm⌫",
275
+ void 0
276
+ ],
277
+ symbols: {
278
+ "↵": "Enter",
279
+ "⌫": "bsp"
280
+ },
281
+ highlight: ["↵", "⌫"],
282
+ disabled: [],
283
+ xl: [],
284
+ l: ["↵", "⌫"],
285
+ supportsDragCursor: !1
254
286
  };
255
287
  /** Custom error class for workshop import failures */
256
- var s = class extends Error {
288
+ var c = class extends Error {
257
289
  constructor(e, t, n) {
258
290
  super(t), this.type = e, this.originalError = n, this.name = "EditorImportError";
259
291
  }
260
292
  };
261
- export { s as EditorImportError, o as createPuzzmoSDK };
293
+ export { c as EditorImportError, o as createPuzzmoSDK, s as defaultKeyboardConfig };
262
294
 
263
295
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/sdk.ts","../src/editor.ts"],"sourcesContent":["import type { MessagesSentFromEmbed, MessagesReceived, GamePlay, AugmentationConfig, CheckpointConfig, Theme, Deed } from \"./types\"\n\nexport type SDK = ReturnType<typeof createPuzzmoSDK>\n\nexport interface PuzzmoSDKOptions {\n /** Optional timeout in ms to wait for READY_DATA (default: 5000) */\n timeout?: number\n}\n\ntype SupportedOutgoingMessages = Pick<\n MessagesSentFromEmbed,\n | \"READY\"\n | \"READY_GAME_LOADED\"\n | \"GAME_COMPLETED\"\n | \"SHOW_GAME_COMPLETE_SCREEN\"\n | \"TIMER_TICK\"\n | \"TIMER_SYNC\"\n | \"UPLOAD_NEW_GAME_STATE\"\n | \"HIT_CHECKPOINT\"\n>\n\ntype SupportedIncomingMessages = Pick<\n MessagesReceived,\n \"READY_DATA\" | \"START_GAME\" | \"PAUSE_GAME\" | \"RESUME_GAME\" | \"SETTINGS_UPDATE\" | \"RETRY_PUZZLE\"\n>\n\ntype MessageHandler<T extends keyof SupportedIncomingMessages> = (data: SupportedIncomingMessages[T]) => void\n\nexport type SDKEventMap = {\n start: void\n pause: void\n resume: void\n retry: void\n settingsUpdate: any\n}\n\nexport type SDKEventType = keyof SDKEventMap\n\nexport interface SDKTimer {\n /** Get elapsed time in milliseconds */\n timeMs: () => number\n /** Get elapsed time in seconds */\n timeSecs: () => number\n /** Get added/penalty time in milliseconds */\n addedTimeMs: () => number\n /** Get added/penalty time in seconds */\n addedTimeSecs: () => number\n /** Get elapsed time without penalties in seconds */\n timeWithoutPenaltySecs: () => number\n /** Get formatted display strings [elapsed, added] */\n display: () => [string, string]\n /** Add penalty time in milliseconds */\n addPenalty: (ms: number) => void\n /** Check if timer is paused */\n isPaused: () => boolean\n /** Check if timer has been started */\n isRunning: () => boolean\n}\n\nfunction formatTime(timeMs: number): string {\n const isAnHourOrMore = timeMs >= 60 * 60 * 1000\n return new Date(timeMs)\n .toISOString()\n .slice(isAnHourOrMore ? 11 : 14, -1)\n .split(\".\")[0]\n}\n\nfunction createTimer(\n initialTimeMs = 0,\n initialAddedTimeMs = 0,\n): SDKTimer & {\n _init: () => void\n _pause: () => void\n _resume: () => void\n _reset: (initialTimeMs?: number, initialAddedTimeMs?: number) => void\n _conclude: () => void\n} {\n let baseTime = initialTimeMs\n let addedTime = initialAddedTimeMs\n let pausedTime = 0\n let concludeTime: number | undefined\n\n let startDate: number | undefined = undefined\n let pausedDate: number | undefined = undefined\n\n const getTime = (): number => {\n if (startDate === undefined) return baseTime + addedTime\n if (concludeTime !== undefined) return concludeTime\n const now = pausedDate ?? performance.now()\n const elapsed = now - startDate - pausedTime\n return baseTime + addedTime + elapsed\n }\n\n return {\n _init: () => {\n if (startDate === undefined) {\n startDate = performance.now()\n pausedDate = undefined\n }\n },\n _pause: () => {\n if (pausedDate !== undefined || startDate === undefined) return\n pausedDate = performance.now()\n },\n _resume: () => {\n if (pausedDate === undefined) return\n pausedTime += performance.now() - pausedDate\n pausedDate = undefined\n },\n _reset: (newInitialTimeMs = 0, newInitialAddedTimeMs = 0) => {\n baseTime = newInitialTimeMs\n addedTime = newInitialAddedTimeMs\n pausedTime = 0\n concludeTime = undefined\n startDate = undefined\n pausedDate = undefined\n },\n _conclude: () => {\n if (pausedDate !== undefined) {\n concludeTime = getTime()\n return\n }\n if (startDate === undefined) {\n concludeTime = baseTime + addedTime\n return\n }\n concludeTime = getTime()\n },\n timeMs: () => getTime(),\n timeSecs: () => getTime() / 1000,\n addedTimeMs: () => addedTime,\n addedTimeSecs: () => addedTime / 1000,\n timeWithoutPenaltySecs: () => (getTime() - addedTime) / 1000,\n addPenalty: (ms: number) => {\n addedTime += ms\n },\n isPaused: () => pausedDate !== undefined || startDate === undefined,\n isRunning: () => startDate !== undefined && pausedDate === undefined,\n display: () => {\n const elapsed = getTime() - addedTime\n const elapsedStr = formatTime(Math.max(0, elapsed))\n const addedStr = addedTime === 0 ? \"\" : formatTime(addedTime)\n return [elapsedStr, addedStr]\n },\n }\n}\n\nfunction createHostAPI() {\n const messageHandlers = new Map<string, Set<(data: any) => void>>()\n\n const sendMessage = <T extends keyof SupportedOutgoingMessages>(type: T, json: SupportedOutgoingMessages[T]) => {\n const message = { type, json, _: \"p\", __: \"mp\", private: true }\n\n if (\"parent\" in window && window.parent !== window) window.parent.postMessage(message, \"*\")\n\n window.postMessage(message, \"*\")\n\n if (\"webkit\" in window && (window as any).webkit?.messageHandlers?.app) (window as any).webkit.messageHandlers.app.postMessage(message)\n\n if (\"puzzmoMessageString\" in window) (window as any).puzzmoMessageString(JSON.stringify(message))\n\n if (\"ReactNativeWebView\" in window && (window as any).ReactNativeWebView?.postMessage)\n (window as any).ReactNativeWebView.postMessage(JSON.stringify(message))\n\n if (type !== \"TIMER_TICK\" && type !== \"TIMER_SYNC\") console.log(\"[Puzzmo SDK] sent:\", type, json)\n }\n\n const onMessage = <T extends keyof SupportedIncomingMessages>(type: T, handler: MessageHandler<T>) => {\n if (!messageHandlers.has(type)) messageHandlers.set(type, new Set())\n messageHandlers.get(type)!.add(handler)\n\n return () => {\n messageHandlers.get(type)?.delete(handler)\n }\n }\n\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"message\", (event) => {\n if (!event?.data?.type) return\n const msgType = event.data.type as string\n const handlers = messageHandlers.get(msgType)\n if (handlers) {\n const msgData = event.data.data ?? event.data.json ?? {}\n if (msgType !== \"TIMER_TICK\" && msgType !== \"TIMER_SYNC\") console.log(\"[Puzzmo SDK] received:\", msgType, msgData)\n handlers.forEach((handler) => handler(msgData))\n }\n })\n }\n\n return { sendMessage, onMessage }\n}\n\nconst hostAPI = createHostAPI()\n\n/** Creates a Puzzmo SDK instance for communicating with the Puzzmo host */\nexport const createPuzzmoSDK = (options: PuzzmoSDKOptions = {}) => {\n let readyData: MessagesReceived[\"READY_DATA\"] | null = null\n let readyDataResolve: ((data: MessagesReceived[\"READY_DATA\"]) => void) | null = null\n\n const getGameplay = () => readyData?.startOrFindGameplay?.gamePlayed\n const getGameplayID = () => getGameplay()?.id ?? null\n const getPuzzleString = () => getGameplay()?.puzzle.puzzle ?? null\n const getBoardState = () => getGameplay()?.boardState ?? null\n const getTheme = () => readyData?.theme ?? null\n const getCompleted = () => getGameplay()?.completed ?? false\n\n const eventListeners = new Map<SDKEventType, Set<(data?: any) => void>>()\n\n const internalTimer = createTimer()\n let timerTickInterval: ReturnType<typeof setInterval> | null = null\n let timerSyncInterval: ReturnType<typeof setInterval> | null = null\n\n const startTimerIntervals = () => {\n if (timerTickInterval) return\n\n timerTickInterval = setInterval(() => {\n if (internalTimer.isPaused()) return\n const [elapsed, added] = internalTimer.display()\n hostAPI.sendMessage(\"TIMER_TICK\", { display: [elapsed, added] })\n }, 500)\n\n timerSyncInterval = setInterval(() => {\n if (internalTimer.isPaused()) return\n hostAPI.sendMessage(\"TIMER_SYNC\", Math.floor(internalTimer.timeWithoutPenaltySecs()))\n }, 10000)\n }\n\n const stopTimerIntervals = () => {\n if (timerTickInterval) {\n clearInterval(timerTickInterval)\n timerTickInterval = null\n }\n if (timerSyncInterval) {\n clearInterval(timerSyncInterval)\n timerSyncInterval = null\n }\n }\n\n const emit = <T extends SDKEventType>(event: T, data?: SDKEventMap[T]) => {\n const listeners = eventListeners.get(event)\n if (listeners) listeners.forEach((listener) => listener(data))\n }\n\n hostAPI.onMessage(\"START_GAME\", () => {\n internalTimer._init()\n startTimerIntervals()\n emit(\"start\")\n })\n\n hostAPI.onMessage(\"PAUSE_GAME\", () => {\n internalTimer._pause()\n emit(\"pause\")\n })\n\n hostAPI.onMessage(\"RESUME_GAME\", () => {\n internalTimer._resume()\n emit(\"resume\")\n })\n\n hostAPI.onMessage(\"SETTINGS_UPDATE\", (data) => emit(\"settingsUpdate\", data))\n\n hostAPI.onMessage(\"RETRY_PUZZLE\", () => {\n internalTimer._reset()\n stopTimerIntervals()\n emit(\"retry\")\n })\n\n hostAPI.onMessage(\"READY_DATA\", (data) => {\n const bootstrapData = data as MessagesReceived[\"READY_DATA\"]\n readyData = bootstrapData\n\n const gamePlayed = bootstrapData.startOrFindGameplay?.gamePlayed\n if (gamePlayed) {\n const existingTime = (gamePlayed.elapsedTimeSecs ?? 0) * 1000\n const existingAddedTime = (gamePlayed.additionalTimeAddedSecs ?? 0) * 1000\n internalTimer._reset(existingTime, existingAddedTime)\n }\n\n if (readyDataResolve) {\n readyDataResolve(bootstrapData)\n readyDataResolve = null\n }\n })\n\n const timer: SDKTimer = {\n timeMs: () => internalTimer.timeMs(),\n timeSecs: () => internalTimer.timeSecs(),\n addedTimeMs: () => internalTimer.addedTimeMs(),\n addedTimeSecs: () => internalTimer.addedTimeSecs(),\n timeWithoutPenaltySecs: () => internalTimer.timeWithoutPenaltySecs(),\n display: () => internalTimer.display(),\n addPenalty: (ms: number) => internalTimer.addPenalty(ms),\n isPaused: () => internalTimer.isPaused(),\n isRunning: () => internalTimer.isRunning(),\n }\n\n return {\n timer,\n\n gameReady: async (): Promise<{\n puzzleString: string\n boardState: string | null\n theme: Theme | null\n completed: boolean\n readyData: MessagesReceived[\"READY_DATA\"] | null\n }> => {\n hostAPI.sendMessage(\"READY\", {})\n\n if (getPuzzleString()) {\n return {\n puzzleString: getPuzzleString()!,\n boardState: getBoardState(),\n theme: getTheme(),\n completed: getCompleted(),\n readyData,\n }\n }\n\n const timeout = options.timeout ?? 5000\n const readyDataPromise = new Promise<MessagesReceived[\"READY_DATA\"]>((resolve, reject) => {\n readyDataResolve = resolve\n setTimeout(() => {\n if (readyDataResolve) {\n readyDataResolve = null\n reject(new Error(`Timeout waiting for READY_DATA after ${timeout}ms`))\n }\n }, timeout)\n })\n\n await readyDataPromise\n\n const puzzleString = getPuzzleString()\n if (!puzzleString) throw new Error(\"READY_DATA received but no puzzle data found\")\n\n return {\n puzzleString,\n boardState: getBoardState(),\n theme: getTheme(),\n completed: getCompleted(),\n readyData,\n }\n },\n\n gameLoaded: (state: any = {}) => {\n hostAPI.sendMessage(\"READY_GAME_LOADED\", {\n state,\n gameRuntimeContract: \"1.0\",\n embedRuntimeContract: \"1.0\",\n })\n },\n\n on: <T extends SDKEventType>(event: T, listener: (data?: SDKEventMap[T]) => void): (() => void) => {\n if (!eventListeners.has(event)) eventListeners.set(event, new Set())\n eventListeners.get(event)!.add(listener)\n return () => {\n eventListeners.get(event)?.delete(listener)\n }\n },\n\n off: <T extends SDKEventType>(event: T, listener: (data?: SDKEventMap[T]) => void) => {\n eventListeners.get(event)?.delete(listener)\n },\n\n updateGameState: (inputString: string, play?: Partial<GamePlay>) => {\n const gameplayID = getGameplayID()\n if (!gameplayID) return\n\n hostAPI.sendMessage(\"UPLOAD_NEW_GAME_STATE\", {\n id: gameplayID,\n input: {\n boardState: inputString,\n elapsedTimeSecs: play?.elapsedTimeSecs ?? internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: play?.additionalTimeAddedSecs ?? internalTimer.addedTimeSecs(),\n collabUserReferences: [],\n },\n })\n },\n\n gameCompleted: (play: Partial<GamePlay>, config?: AugmentationConfig) => {\n internalTimer._conclude()\n stopTimerIntervals()\n\n const finalPlay: Partial<GamePlay> = {\n ...play,\n elapsedTimeSecs: play.elapsedTimeSecs ?? internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: play.additionalTimeAddedSecs ?? internalTimer.addedTimeSecs(),\n }\n\n const deeds: Deed[] = (config?.deeds as any) ?? []\n deeds.push({ id: \"points\", value: play.pointsAwarded })\n deeds.push({\n id: \"time\",\n value: Math.round(finalPlay.elapsedTimeSecs ?? 0) + Math.round(finalPlay.additionalTimeAddedSecs ?? 0),\n })\n\n const gameplayID = getGameplayID()\n if (gameplayID) {\n hostAPI.sendMessage(\"GAME_COMPLETED\", {\n id: gameplayID,\n input: finalPlay,\n config,\n })\n }\n },\n\n showCompletionScreen: (results: any[], gameplay: GamePlay, showRetry = true) => {\n hostAPI.sendMessage(\"SHOW_GAME_COMPLETE_SCREEN\", {\n results,\n showRetry,\n gameplay,\n })\n },\n\n hitCheckpoint: (checkpointName: string, checkpointConfig: CheckpointConfig, config?: AugmentationConfig) => {\n const gameplayID = getGameplayID()\n if (!gameplayID) return\n\n const inputStr = getBoardState() ?? \"\"\n const play: Partial<GamePlay> = {\n elapsedTimeSecs: internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: internalTimer.addedTimeSecs(),\n }\n\n hostAPI.sendMessage(\"HIT_CHECKPOINT\", {\n checkpointName,\n gameplay: { inputStr, play },\n checkpointConfig,\n augConfig: config ?? {},\n })\n },\n\n _hostAPI: hostAPI,\n }\n}\n","/** Severity level for validation issues */\nexport type ValidationLevel = \"error\" | \"warning\" | \"info\"\n\n/** Represents a single validation issue found during puzzle validation */\nexport interface ValidationIssue {\n level: ValidationLevel\n message: string\n line?: number\n col?: number\n length?: number\n}\n\n/** Complete validation report for a puzzle */\nexport interface ValidationReport {\n success: boolean\n issues: ValidationIssue[]\n}\n\nexport type ImportErrorType = \"invalid_format\" | \"parsing_error\" | \"unknown\"\n\n/** Custom error class for workshop import failures */\nexport class EditorImportError extends Error {\n constructor(\n public type: ImportErrorType,\n message: string,\n public originalError?: unknown,\n ) {\n super(message)\n this.name = \"EditorImportError\"\n }\n}\n\n/** Result of a successful puzzle import operation */\nexport interface ImportResult {\n data: string\n warnings?: ValidationIssue[]\n title?: string\n authors?: string[]\n editors?: string[]\n}\n\n/** Settings UI descriptor returned by an editor bundle */\nexport interface EditorBundleSettings<TComponent = unknown> {\n components: TComponent[]\n defaults: Record<string, unknown>\n}\n\n/** Main interface for a Workshop bundle */\nexport interface EditorBundle<TSettingsComponent = unknown> {\n validator: {\n validate(data: string): Promise<ValidationReport> | ValidationReport\n }\n importer?: {\n onImport(filename: string, contents: string | ArrayBuffer): Promise<ImportResult> | ImportResult\n }\n /** Embed-level settings UI, populated from the bundle's declared settings */\n settings?: EditorBundleSettings<TSettingsComponent>\n /** Editor-level settings UI, populated from the bundle's declared editor settings */\n editorSettings?: EditorBundleSettings<TSettingsComponent>\n /** Custom puzzle editor, if provided by the bundle */\n editor?: {\n mount(...args: unknown[]): unknown\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/sdk.ts","../src/keyboard.ts","../src/editor.ts"],"sourcesContent":["import type {\n MessagesSentFromEmbed,\n MessagesReceived,\n GamePlay,\n AugmentationConfig,\n CheckpointConfig,\n Theme,\n Deed,\n KeyboardConfig,\n} from \"./types\"\n\nexport type SDK = ReturnType<typeof createPuzzmoSDK>\n\nexport interface PuzzmoSDKOptions {\n /** Optional timeout in ms to wait for READY_DATA (default: 5000) */\n timeout?: number\n}\n\ntype SupportedOutgoingMessages = Pick<\n MessagesSentFromEmbed,\n | \"READY\"\n | \"READY_GAME_LOADED\"\n | \"GAME_COMPLETED\"\n | \"SHOW_GAME_COMPLETE_SCREEN\"\n | \"TIMER_TICK\"\n | \"TIMER_SYNC\"\n | \"UPLOAD_NEW_GAME_STATE\"\n | \"HIT_CHECKPOINT\"\n | \"KEYBOARD_UPDATE_CONFIG\"\n>\n\ntype SupportedIncomingMessages = Pick<\n MessagesReceived,\n | \"READY_DATA\"\n | \"START_GAME\"\n | \"PAUSE_GAME\"\n | \"RESUME_GAME\"\n | \"SETTINGS_UPDATE\"\n | \"RETRY_PUZZLE\"\n | \"KEYBOARD_KEY_PRESS\"\n | \"KEYBOARD_CURSOR_CHANGE\"\n | \"KEYBOARD_CURSOR_END\"\n>\n\ntype MessageHandler<T extends keyof SupportedIncomingMessages> = (data: SupportedIncomingMessages[T]) => void\n\nexport type SDKEventMap = {\n start: void\n pause: void\n resume: void\n retry: void\n settingsUpdate: any\n /** A key on the on-screen keyboard was tapped. */\n keyboardKeyPress: { key: string }\n /** The drag cursor moved across the keyboard. Only fires when `supportsDragCursor` is true. */\n keyboardCursorChange: { position: [number, number] }\n /** The drag cursor was released. Only fires when `supportsDragCursor` is true. */\n keyboardCursorEnd: void\n}\n\nexport type SDKEventType = keyof SDKEventMap\n\nexport interface SDKTimer {\n /** Get elapsed time in milliseconds */\n timeMs: () => number\n /** Get elapsed time in seconds */\n timeSecs: () => number\n /** Get added/penalty time in milliseconds */\n addedTimeMs: () => number\n /** Get added/penalty time in seconds */\n addedTimeSecs: () => number\n /** Get elapsed time without penalties in seconds */\n timeWithoutPenaltySecs: () => number\n /** Get formatted display strings [elapsed, added] */\n display: () => [string, string]\n /** Add penalty time in milliseconds */\n addPenalty: (ms: number) => void\n /** Check if timer is paused */\n isPaused: () => boolean\n /** Check if timer has been started */\n isRunning: () => boolean\n}\n\nfunction formatTime(timeMs: number): string {\n const isAnHourOrMore = timeMs >= 60 * 60 * 1000\n return new Date(timeMs)\n .toISOString()\n .slice(isAnHourOrMore ? 11 : 14, -1)\n .split(\".\")[0]\n}\n\nfunction createTimer(\n initialTimeMs = 0,\n initialAddedTimeMs = 0,\n): SDKTimer & {\n _init: () => void\n _pause: () => void\n _resume: () => void\n _reset: (initialTimeMs?: number, initialAddedTimeMs?: number) => void\n _conclude: () => void\n} {\n let baseTime = initialTimeMs\n let addedTime = initialAddedTimeMs\n let pausedTime = 0\n let concludeTime: number | undefined\n\n let startDate: number | undefined = undefined\n let pausedDate: number | undefined = undefined\n\n const getTime = (): number => {\n if (startDate === undefined) return baseTime + addedTime\n if (concludeTime !== undefined) return concludeTime\n const now = pausedDate ?? performance.now()\n const elapsed = now - startDate - pausedTime\n return baseTime + addedTime + elapsed\n }\n\n return {\n _init: () => {\n if (startDate === undefined) {\n startDate = performance.now()\n pausedDate = undefined\n }\n },\n _pause: () => {\n if (pausedDate !== undefined || startDate === undefined) return\n pausedDate = performance.now()\n },\n _resume: () => {\n if (pausedDate === undefined) return\n pausedTime += performance.now() - pausedDate\n pausedDate = undefined\n },\n _reset: (newInitialTimeMs = 0, newInitialAddedTimeMs = 0) => {\n baseTime = newInitialTimeMs\n addedTime = newInitialAddedTimeMs\n pausedTime = 0\n concludeTime = undefined\n startDate = undefined\n pausedDate = undefined\n },\n _conclude: () => {\n if (pausedDate !== undefined) {\n concludeTime = getTime()\n return\n }\n if (startDate === undefined) {\n concludeTime = baseTime + addedTime\n return\n }\n concludeTime = getTime()\n },\n timeMs: () => getTime(),\n timeSecs: () => getTime() / 1000,\n addedTimeMs: () => addedTime,\n addedTimeSecs: () => addedTime / 1000,\n timeWithoutPenaltySecs: () => (getTime() - addedTime) / 1000,\n addPenalty: (ms: number) => {\n addedTime += ms\n },\n isPaused: () => pausedDate !== undefined || startDate === undefined,\n isRunning: () => startDate !== undefined && pausedDate === undefined,\n display: () => {\n const elapsed = getTime() - addedTime\n const elapsedStr = formatTime(Math.max(0, elapsed))\n const addedStr = addedTime === 0 ? \"\" : formatTime(addedTime)\n return [elapsedStr, addedStr]\n },\n }\n}\n\nfunction createHostAPI() {\n const messageHandlers = new Map<string, Set<(data: any) => void>>()\n\n const sendMessage = <T extends keyof SupportedOutgoingMessages>(type: T, json: SupportedOutgoingMessages[T]) => {\n const message = { type, json, _: \"p\", __: \"mp\", private: true }\n\n if (\"parent\" in window && window.parent !== window) window.parent.postMessage(message, \"*\")\n\n window.postMessage(message, \"*\")\n\n if (\"webkit\" in window && (window as any).webkit?.messageHandlers?.app) (window as any).webkit.messageHandlers.app.postMessage(message)\n\n if (\"puzzmoMessageString\" in window) (window as any).puzzmoMessageString(JSON.stringify(message))\n\n if (\"ReactNativeWebView\" in window && (window as any).ReactNativeWebView?.postMessage)\n (window as any).ReactNativeWebView.postMessage(JSON.stringify(message))\n\n if (type !== \"TIMER_TICK\" && type !== \"TIMER_SYNC\") console.log(\"[Puzzmo SDK] sent:\", type, json)\n }\n\n const onMessage = <T extends keyof SupportedIncomingMessages>(type: T, handler: MessageHandler<T>) => {\n if (!messageHandlers.has(type)) messageHandlers.set(type, new Set())\n messageHandlers.get(type)!.add(handler)\n\n return () => {\n messageHandlers.get(type)?.delete(handler)\n }\n }\n\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"message\", (event) => {\n if (!event?.data?.type) return\n const msgType = event.data.type as string\n const handlers = messageHandlers.get(msgType)\n if (handlers) {\n const msgData = event.data.data ?? event.data.json ?? {}\n if (msgType !== \"TIMER_TICK\" && msgType !== \"TIMER_SYNC\") console.log(\"[Puzzmo SDK] received:\", msgType, msgData)\n handlers.forEach((handler) => handler(msgData))\n }\n })\n }\n\n return { sendMessage, onMessage }\n}\n\nconst hostAPI = createHostAPI()\n\n/** Creates a Puzzmo SDK instance for communicating with the Puzzmo host */\nexport const createPuzzmoSDK = (options: PuzzmoSDKOptions = {}) => {\n let readyData: MessagesReceived[\"READY_DATA\"] | null = null\n let readyDataResolve: ((data: MessagesReceived[\"READY_DATA\"]) => void) | null = null\n\n const getGameplay = () => readyData?.startOrFindGameplay?.gamePlayed\n const getGameplayID = () => getGameplay()?.id ?? null\n const getPuzzleString = () => getGameplay()?.puzzle.puzzle ?? null\n const getBoardState = () => getGameplay()?.boardState ?? null\n const getTheme = () => readyData?.theme ?? null\n const getCompleted = () => getGameplay()?.completed ?? false\n\n const eventListeners = new Map<SDKEventType, Set<(data?: any) => void>>()\n\n const internalTimer = createTimer()\n let timerTickInterval: ReturnType<typeof setInterval> | null = null\n let timerSyncInterval: ReturnType<typeof setInterval> | null = null\n\n const startTimerIntervals = () => {\n if (timerTickInterval) return\n\n timerTickInterval = setInterval(() => {\n if (internalTimer.isPaused()) return\n const [elapsed, added] = internalTimer.display()\n hostAPI.sendMessage(\"TIMER_TICK\", { display: [elapsed, added] })\n }, 500)\n\n timerSyncInterval = setInterval(() => {\n if (internalTimer.isPaused()) return\n hostAPI.sendMessage(\"TIMER_SYNC\", Math.floor(internalTimer.timeWithoutPenaltySecs()))\n }, 10000)\n }\n\n const stopTimerIntervals = () => {\n if (timerTickInterval) {\n clearInterval(timerTickInterval)\n timerTickInterval = null\n }\n if (timerSyncInterval) {\n clearInterval(timerSyncInterval)\n timerSyncInterval = null\n }\n }\n\n const emit = <T extends SDKEventType>(event: T, data?: SDKEventMap[T]) => {\n const listeners = eventListeners.get(event)\n if (listeners) listeners.forEach((listener) => listener(data))\n }\n\n hostAPI.onMessage(\"START_GAME\", () => {\n internalTimer._init()\n startTimerIntervals()\n emit(\"start\")\n })\n\n hostAPI.onMessage(\"PAUSE_GAME\", () => {\n internalTimer._pause()\n emit(\"pause\")\n })\n\n hostAPI.onMessage(\"RESUME_GAME\", () => {\n internalTimer._resume()\n emit(\"resume\")\n })\n\n hostAPI.onMessage(\"SETTINGS_UPDATE\", (data) => emit(\"settingsUpdate\", data))\n\n hostAPI.onMessage(\"KEYBOARD_KEY_PRESS\", (data) => emit(\"keyboardKeyPress\", data))\n hostAPI.onMessage(\"KEYBOARD_CURSOR_CHANGE\", (data) => emit(\"keyboardCursorChange\", data))\n hostAPI.onMessage(\"KEYBOARD_CURSOR_END\", () => emit(\"keyboardCursorEnd\"))\n\n hostAPI.onMessage(\"RETRY_PUZZLE\", () => {\n internalTimer._reset()\n stopTimerIntervals()\n emit(\"retry\")\n })\n\n hostAPI.onMessage(\"READY_DATA\", (data) => {\n const bootstrapData = data as MessagesReceived[\"READY_DATA\"]\n readyData = bootstrapData\n\n const gamePlayed = bootstrapData.startOrFindGameplay?.gamePlayed\n if (gamePlayed) {\n const existingTime = (gamePlayed.elapsedTimeSecs ?? 0) * 1000\n const existingAddedTime = (gamePlayed.additionalTimeAddedSecs ?? 0) * 1000\n internalTimer._reset(existingTime, existingAddedTime)\n }\n\n if (readyDataResolve) {\n readyDataResolve(bootstrapData)\n readyDataResolve = null\n }\n })\n\n const timer: SDKTimer = {\n timeMs: () => internalTimer.timeMs(),\n timeSecs: () => internalTimer.timeSecs(),\n addedTimeMs: () => internalTimer.addedTimeMs(),\n addedTimeSecs: () => internalTimer.addedTimeSecs(),\n timeWithoutPenaltySecs: () => internalTimer.timeWithoutPenaltySecs(),\n display: () => internalTimer.display(),\n addPenalty: (ms: number) => internalTimer.addPenalty(ms),\n isPaused: () => internalTimer.isPaused(),\n isRunning: () => internalTimer.isRunning(),\n }\n\n return {\n timer,\n\n gameReady: async (): Promise<{\n puzzleString: string\n boardState: string | null\n theme: Theme | null\n completed: boolean\n readyData: MessagesReceived[\"READY_DATA\"] | null\n }> => {\n hostAPI.sendMessage(\"READY\", {})\n\n if (getPuzzleString()) {\n return {\n puzzleString: getPuzzleString()!,\n boardState: getBoardState(),\n theme: getTheme(),\n completed: getCompleted(),\n readyData,\n }\n }\n\n const timeout = options.timeout ?? 5000\n const readyDataPromise = new Promise<MessagesReceived[\"READY_DATA\"]>((resolve, reject) => {\n readyDataResolve = resolve\n setTimeout(() => {\n if (readyDataResolve) {\n readyDataResolve = null\n reject(new Error(`Timeout waiting for READY_DATA after ${timeout}ms`))\n }\n }, timeout)\n })\n\n await readyDataPromise\n\n const puzzleString = getPuzzleString()\n if (!puzzleString) throw new Error(\"READY_DATA received but no puzzle data found\")\n\n return {\n puzzleString,\n boardState: getBoardState(),\n theme: getTheme(),\n completed: getCompleted(),\n readyData,\n }\n },\n\n gameLoaded: (state: any = {}) => {\n hostAPI.sendMessage(\"READY_GAME_LOADED\", {\n state,\n gameRuntimeContract: \"1.0\",\n embedRuntimeContract: \"1.0\",\n })\n },\n\n on: <T extends SDKEventType>(event: T, listener: (data?: SDKEventMap[T]) => void): (() => void) => {\n if (!eventListeners.has(event)) eventListeners.set(event, new Set())\n eventListeners.get(event)!.add(listener)\n return () => {\n eventListeners.get(event)?.delete(listener)\n }\n },\n\n off: <T extends SDKEventType>(event: T, listener: (data?: SDKEventMap[T]) => void) => {\n eventListeners.get(event)?.delete(listener)\n },\n\n updateGameState: (inputString: string, play?: Partial<GamePlay>) => {\n const gameplayID = getGameplayID()\n if (!gameplayID) return\n\n hostAPI.sendMessage(\"UPLOAD_NEW_GAME_STATE\", {\n id: gameplayID,\n input: {\n boardState: inputString,\n elapsedTimeSecs: play?.elapsedTimeSecs ?? internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: play?.additionalTimeAddedSecs ?? internalTimer.addedTimeSecs(),\n collabUserReferences: [],\n },\n })\n },\n\n gameCompleted: (play: Partial<GamePlay>, config?: AugmentationConfig) => {\n internalTimer._conclude()\n stopTimerIntervals()\n\n const finalPlay: Partial<GamePlay> = {\n ...play,\n elapsedTimeSecs: play.elapsedTimeSecs ?? internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: play.additionalTimeAddedSecs ?? internalTimer.addedTimeSecs(),\n }\n\n const deeds: Deed[] = (config?.deeds as any) ?? []\n deeds.push({ id: \"points\", value: play.pointsAwarded })\n deeds.push({\n id: \"time\",\n value: Math.round(finalPlay.elapsedTimeSecs ?? 0) + Math.round(finalPlay.additionalTimeAddedSecs ?? 0),\n })\n\n const gameplayID = getGameplayID()\n if (gameplayID) {\n hostAPI.sendMessage(\"GAME_COMPLETED\", {\n id: gameplayID,\n input: finalPlay,\n config,\n })\n }\n },\n\n showCompletionScreen: (results: any[], gameplay: GamePlay, showRetry = true) => {\n hostAPI.sendMessage(\"SHOW_GAME_COMPLETE_SCREEN\", {\n results,\n showRetry,\n gameplay,\n })\n },\n\n hitCheckpoint: (checkpointName: string, checkpointConfig: CheckpointConfig, config?: AugmentationConfig) => {\n const gameplayID = getGameplayID()\n if (!gameplayID) return\n\n const inputStr = getBoardState() ?? \"\"\n const play: Partial<GamePlay> = {\n elapsedTimeSecs: internalTimer.timeWithoutPenaltySecs(),\n additionalTimeAddedSecs: internalTimer.addedTimeSecs(),\n }\n\n hostAPI.sendMessage(\"HIT_CHECKPOINT\", {\n checkpointName,\n gameplay: { inputStr, play },\n checkpointConfig,\n augConfig: config ?? {},\n })\n },\n\n keyboard: {\n /** Show the on-screen keyboard with the given config. Call again to update state (e.g. to change disabled keys). */\n show: (config: KeyboardConfig) => {\n hostAPI.sendMessage(\"KEYBOARD_UPDATE_CONFIG\", config)\n },\n /** Hide the on-screen keyboard. */\n hide: () => {\n hostAPI.sendMessage(\"KEYBOARD_UPDATE_CONFIG\", {\n layout: [],\n symbols: {},\n highlight: [],\n disabled: [],\n xl: [],\n l: [],\n supportsDragCursor: false,\n })\n },\n },\n\n _hostAPI: hostAPI,\n }\n}\n","import type { KeyboardConfig } from \"./types\"\n\n/**\n * A standard QWERTY layout with Enter and Backspace — a reasonable default for\n * any game that needs text input. Customize from here by spreading and overriding.\n *\n * @example\n * // Use as-is\n * sdk.keyboard.show(defaultKeyboardConfig)\n *\n * @example\n * // Extend with dynamic disabled letters\n * sdk.keyboard.show({ ...defaultKeyboardConfig, disabled: usedLetters })\n */\nexport const defaultKeyboardConfig: KeyboardConfig = {\n layout: [\"qwertyuiop\", \"asdfghjkl\", \"↵zxcvbnm⌫\", undefined],\n symbols: { \"↵\": \"Enter\", \"⌫\": \"bsp\" },\n highlight: [\"↵\", \"⌫\"],\n disabled: [],\n xl: [],\n l: [\"↵\", \"⌫\"],\n supportsDragCursor: false,\n}\n","/** Severity level for validation issues */\nexport type ValidationLevel = \"error\" | \"warning\" | \"info\"\n\n/** Represents a single validation issue found during puzzle validation */\nexport interface ValidationIssue {\n level: ValidationLevel\n message: string\n line?: number\n col?: number\n length?: number\n}\n\n/** Complete validation report for a puzzle */\nexport interface ValidationReport {\n success: boolean\n issues: ValidationIssue[]\n}\n\nexport type ImportErrorType = \"invalid_format\" | \"parsing_error\" | \"unknown\"\n\n/** Custom error class for workshop import failures */\nexport class EditorImportError extends Error {\n constructor(\n public type: ImportErrorType,\n message: string,\n public originalError?: unknown,\n ) {\n super(message)\n this.name = \"EditorImportError\"\n }\n}\n\n/** Result of a successful puzzle import operation */\nexport interface ImportResult {\n data: string\n warnings?: ValidationIssue[]\n title?: string\n authors?: string[]\n editors?: string[]\n}\n\n/** Settings UI descriptor returned by an editor bundle */\nexport interface EditorBundleSettings<TComponent = unknown> {\n components: TComponent[]\n defaults: Record<string, unknown>\n}\n\n/** Main interface for a Workshop bundle */\nexport interface EditorBundle<TSettingsComponent = unknown> {\n validator: {\n validate(data: string): Promise<ValidationReport> | ValidationReport\n }\n importer?: {\n onImport(filename: string, contents: string | ArrayBuffer): Promise<ImportResult> | ImportResult\n }\n /** Embed-level settings UI, populated from the bundle's declared settings */\n settings?: EditorBundleSettings<TSettingsComponent>\n /** Editor-level settings UI, populated from the bundle's declared editor settings */\n editorSettings?: EditorBundleSettings<TSettingsComponent>\n /** Custom puzzle editor, if provided by the bundle */\n editor?: {\n mount(...args: unknown[]): unknown\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { KeyboardConfig } from "./types";
2
+ /**
3
+ * A standard QWERTY layout with Enter and Backspace — a reasonable default for
4
+ * any game that needs text input. Customize from here by spreading and overriding.
5
+ *
6
+ * @example
7
+ * // Use as-is
8
+ * sdk.keyboard.show(defaultKeyboardConfig)
9
+ *
10
+ * @example
11
+ * // Extend with dynamic disabled letters
12
+ * sdk.keyboard.show({ ...defaultKeyboardConfig, disabled: usedLetters })
13
+ */
14
+ export declare const defaultKeyboardConfig: KeyboardConfig;
15
+ //# sourceMappingURL=keyboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../src/keyboard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,EAAE,cAQnC,CAAA"}
package/dist/sdk.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import type { MessagesSentFromEmbed, MessagesReceived, GamePlay, AugmentationConfig, CheckpointConfig, Theme } from "./types";
1
+ import type { MessagesSentFromEmbed, MessagesReceived, GamePlay, AugmentationConfig, CheckpointConfig, Theme, KeyboardConfig } from "./types";
2
2
  export type SDK = ReturnType<typeof createPuzzmoSDK>;
3
3
  export interface PuzzmoSDKOptions {
4
4
  /** Optional timeout in ms to wait for READY_DATA (default: 5000) */
5
5
  timeout?: number;
6
6
  }
7
- type SupportedOutgoingMessages = Pick<MessagesSentFromEmbed, "READY" | "READY_GAME_LOADED" | "GAME_COMPLETED" | "SHOW_GAME_COMPLETE_SCREEN" | "TIMER_TICK" | "TIMER_SYNC" | "UPLOAD_NEW_GAME_STATE" | "HIT_CHECKPOINT">;
8
- type SupportedIncomingMessages = Pick<MessagesReceived, "READY_DATA" | "START_GAME" | "PAUSE_GAME" | "RESUME_GAME" | "SETTINGS_UPDATE" | "RETRY_PUZZLE">;
7
+ type SupportedOutgoingMessages = Pick<MessagesSentFromEmbed, "READY" | "READY_GAME_LOADED" | "GAME_COMPLETED" | "SHOW_GAME_COMPLETE_SCREEN" | "TIMER_TICK" | "TIMER_SYNC" | "UPLOAD_NEW_GAME_STATE" | "HIT_CHECKPOINT" | "KEYBOARD_UPDATE_CONFIG">;
8
+ type SupportedIncomingMessages = Pick<MessagesReceived, "READY_DATA" | "START_GAME" | "PAUSE_GAME" | "RESUME_GAME" | "SETTINGS_UPDATE" | "RETRY_PUZZLE" | "KEYBOARD_KEY_PRESS" | "KEYBOARD_CURSOR_CHANGE" | "KEYBOARD_CURSOR_END">;
9
9
  type MessageHandler<T extends keyof SupportedIncomingMessages> = (data: SupportedIncomingMessages[T]) => void;
10
10
  export type SDKEventMap = {
11
11
  start: void;
@@ -13,6 +13,16 @@ export type SDKEventMap = {
13
13
  resume: void;
14
14
  retry: void;
15
15
  settingsUpdate: any;
16
+ /** A key on the on-screen keyboard was tapped. */
17
+ keyboardKeyPress: {
18
+ key: string;
19
+ };
20
+ /** The drag cursor moved across the keyboard. Only fires when `supportsDragCursor` is true. */
21
+ keyboardCursorChange: {
22
+ position: [number, number];
23
+ };
24
+ /** The drag cursor was released. Only fires when `supportsDragCursor` is true. */
25
+ keyboardCursorEnd: void;
16
26
  };
17
27
  export type SDKEventType = keyof SDKEventMap;
18
28
  export interface SDKTimer {
@@ -52,6 +62,12 @@ export declare const createPuzzmoSDK: (options?: PuzzmoSDKOptions) => {
52
62
  gameCompleted: (play: Partial<GamePlay>, config?: AugmentationConfig) => void;
53
63
  showCompletionScreen: (results: any[], gameplay: GamePlay, showRetry?: boolean) => void;
54
64
  hitCheckpoint: (checkpointName: string, checkpointConfig: CheckpointConfig, config?: AugmentationConfig) => void;
65
+ keyboard: {
66
+ /** Show the on-screen keyboard with the given config. Call again to update state (e.g. to change disabled keys). */
67
+ show: (config: KeyboardConfig) => void;
68
+ /** Hide the on-screen keyboard. */
69
+ hide: () => void;
70
+ };
55
71
  _hostAPI: {
56
72
  sendMessage: <T extends keyof SupportedOutgoingMessages>(type: T, json: SupportedOutgoingMessages[T]) => void;
57
73
  onMessage: <T extends keyof SupportedIncomingMessages>(type: T, handler: MessageHandler<T>) => () => void;
package/dist/sdk.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -189,14 +189,145 @@ export type ThumbnailConfig = {
189
189
  renderContext?: "preview" | "share" | "completed" | "timeline";
190
190
  viewerMetadata?: any | null;
191
191
  };
192
+ /**
193
+ * Configuration for the Puzzmo on-screen keyboard shown on touch devices.
194
+ *
195
+ * Keys in the layout are single characters. Special/action keys should use non-alphabet
196
+ * Unicode characters (e.g. `"⌫"` for backspace, `"↵"` for enter) so they don't conflict
197
+ * with letter input. Map those characters to display labels via `symbols`.
198
+ *
199
+ * @example
200
+ * // Simple QWERTY keyboard — a good starting point for word games
201
+ *
202
+ * const config: KeyboardConfig = {
203
+ * layout: ["qwertyuiop", "asdfghjkl", "↵zxcvbnm⌫", undefined],
204
+ * symbols: { "↵": "Enter", "⌫": "bsp" },
205
+ * highlight: ["↵", "⌫"],
206
+ * disabled: [],
207
+ * xl: [],
208
+ * l: ["↵", "⌫"],
209
+ * supportsDragCursor: false,
210
+ * }
211
+ *
212
+ * @example
213
+ * // Crossword keyboard — complex layout with two panels, direction controls, and drag cursor.
214
+ * // Special characters are used as action key tokens; symbols maps them to display labels.
215
+ * // The "∂" key flips cursor direction; "≤"/"≥" move between cells; "✱" switches panels.
216
+ *
217
+ * const crosswordConfig: KeyboardConfig = {
218
+ * layout: ["qwertyuiop", "∂asdfghjkl⟳", "≤✱zxcvbnm⌫≥"],
219
+ * symbols: {
220
+ * "∂": "flip-down", // switches cursor direction (emitted as key press "∂")
221
+ * "⟳": "flip-across", // alternate direction flip
222
+ * "≤": "prev", // move cursor to previous cell
223
+ * "≥": "next", // move cursor to next cell
224
+ * "✱": "123", // switch to number/rebus panel
225
+ * "⌫": "bsp", // backspace
226
+ * },
227
+ * highlight: ["∂", "⟳", "≤", "≥", "✱", "⌫"],
228
+ * disabled: [],
229
+ * xl: [],
230
+ * l: [],
231
+ * supportsDragCursor: true, // enables the drag-to-position cursor feature
232
+ * }
233
+ */
234
+ export type KeyboardConfig = {
235
+ /**
236
+ * The key rows to render. Up to 4 rows — pass `undefined` for the 4th row to omit it.
237
+ * Each string is one row; each character is one key. Use non-letter Unicode characters
238
+ * for action keys (backspace, enter, panel-switch, etc.) to avoid input conflicts.
239
+ *
240
+ * Accepts either a 4-tuple `[row1, row2, row3, row4 | undefined]` or a plain array of
241
+ * strings/nulls (null renders an empty row).
242
+ *
243
+ * @example ["qwertyuiop", "asdfghjkl", "↵zxcvbnm⌫", undefined]
244
+ */
245
+ layout: [string, string, string, string | undefined] | (string | null)[];
246
+ /**
247
+ * Maps action-key tokens to the label string displayed on the key face.
248
+ * The token character is what the game receives in a `keyboardKeyPress` event;
249
+ * the label is purely visual.
250
+ *
251
+ * @example { "⌫": "bsp", "↵": "Enter", "✱": "123" }
252
+ */
253
+ symbols: Record<string, string>;
254
+ /**
255
+ * Keys that should render with the highlight/accent background color.
256
+ * Typically used for action keys (backspace, enter, direction keys) so they
257
+ * stand out from the letter keys.
258
+ *
259
+ * @example ["↵", "⌫"]
260
+ */
261
+ highlight: string[];
262
+ /**
263
+ * Keys that are non-interactive and visually dimmed.
264
+ * Update this array dynamically to disable letters that are no longer valid
265
+ * for the current game state (e.g. letters already placed in a word game).
266
+ *
267
+ * @example ["q", "z", "x"] // letters unavailable given current board state
268
+ */
269
+ disabled: string[];
270
+ /**
271
+ * Keys that should render at extra-large width (~17.85% of the keyboard row).
272
+ * Use for high-priority action keys like spacebar or a main confirm key.
273
+ *
274
+ * @example ["␣"]
275
+ */
276
+ xl: string[];
277
+ /**
278
+ * Keys that should render at large width (~14.7% of the keyboard row).
279
+ * Use for secondary action keys like Enter and Backspace that need more touch area.
280
+ *
281
+ * @example ["↵", "⌫"]
282
+ */
283
+ l: string[];
284
+ /**
285
+ * When `true`, the keyboard renders a drag cursor — the player can press-and-hold then
286
+ * drag across the keys to position a cursor before releasing to confirm a character.
287
+ * Listen for `keyboardCursorChange` and `keyboardCursorEnd` events to handle this.
288
+ *
289
+ * Only enable if your game has a spatial input model that benefits from drag-cursor
290
+ * positioning (e.g. selecting a cell in a grid).
291
+ */
292
+ supportsDragCursor: boolean;
293
+ /**
294
+ * Controls horizontal alignment for each row. Index matches the `layout` row index.
295
+ * Defaults to `"center"` for any row not listed.
296
+ *
297
+ * @example ["center", "center", "end", "center"]
298
+ */
299
+ rowPositioning?: ("end" | "start" | "center" | undefined)[];
300
+ /**
301
+ * Keys that expand to fill remaining horizontal space in their row (flex-grow).
302
+ * Useful for a spacebar key that should stretch across the bottom row.
303
+ *
304
+ * @example ["␣"]
305
+ */
306
+ flexGrowSymbols?: string[];
307
+ /**
308
+ * CSS properties applied to every key face. Use for font overrides or color tweaks
309
+ * that apply uniformly across the keyboard.
310
+ *
311
+ * @example { textTransform: "lowercase", color: "#888" }
312
+ */
313
+ keyStyles?: Record<string, string>;
314
+ /**
315
+ * CSS properties applied to the keyboard container element. Use for positioning or
316
+ * background tweaks that apply to the whole keyboard.
317
+ */
318
+ kbdStyles?: Record<string, string>;
319
+ };
192
320
  /** Messages from the SDK to the host */
193
321
  export type MessagesSentFromEmbed = {
322
+ /** Tells the host to send back the bootstrap data (puzzle, theme, gameplay state). Send once on startup via `sdk.gameReady()`. */
194
323
  READY: object;
324
+ /** Signals that the game has finished loading and is ready to start. The host will respond with `START_GAME`. */
195
325
  READY_GAME_LOADED: {
196
326
  state: any;
197
327
  gameRuntimeContract: string;
198
328
  embedRuntimeContract: string;
199
329
  };
330
+ /** Persist the current in-progress game state to the API. Call this after every meaningful player action. */
200
331
  UPLOAD_NEW_GAME_STATE: {
201
332
  id: string;
202
333
  input: {
@@ -210,23 +341,38 @@ export type MessagesSentFromEmbed = {
210
341
  collabUserReferences: string[];
211
342
  };
212
343
  };
344
+ /** Upload the final completed game state. Triggers scoring, deeds, and augmentations on the host. */
213
345
  GAME_COMPLETED: {
346
+ /** The gameplay ID returned from `READY_DATA`. */
214
347
  id: string;
348
+ /** See CompleteGamePlayedInput — elapsed time, board state, score, etc. */
215
349
  input: any;
216
- pipelineStats?: any[];
217
350
  config?: {
351
+ /** Interesting values from the game used for scoring and stats (e.g. points, time). */
218
352
  deeds?: Deed[] | readonly Deed[];
219
353
  };
220
354
  };
355
+ /** Ask the host to show the post-game completion screen. Send after `GAME_COMPLETED`. */
221
356
  SHOW_GAME_COMPLETE_SCREEN: {
357
+ /** @deprecated Components to render in the sidebar — no longer used by the host. */
222
358
  results: GameOverMessageUIComponent[];
359
+ /** Whether to show the retry button — currently ignored by the host but good practice to send. */
223
360
  showRetry: boolean;
361
+ /** The gameplay object that was sent with `GAME_COMPLETED`. */
224
362
  gameplay: GamePlay;
225
363
  };
364
+ /** Update the timer display string shown in the host UI. Sent automatically by the SDK every 500ms. */
226
365
  TIMER_TICK: {
227
366
  display: [string, string];
228
367
  };
368
+ /**
369
+ * Sync the authoritative elapsed time to the host. Used for idle detection and co-op collab state.
370
+ * Sent automatically by the SDK every 10 seconds.
371
+ */
229
372
  TIMER_SYNC: number;
373
+ /** Show or update the on-screen keyboard. Pass the full config each time — the host replaces its entire state. To hide, call `sdk.keyboard.hide()`. */
374
+ KEYBOARD_UPDATE_CONFIG: KeyboardConfig;
375
+ /** Notify the host that a named checkpoint was reached (e.g. completing a sub-puzzle or bonus round). */
230
376
  HIT_CHECKPOINT: {
231
377
  checkpointName: string;
232
378
  gameplay: {
@@ -239,14 +385,31 @@ export type MessagesSentFromEmbed = {
239
385
  };
240
386
  /** Messages from the host to the SDK */
241
387
  export type MessagesReceived = {
388
+ /** The bootstrap payload containing puzzle data, theme, and existing gameplay state. Received in response to `READY`. */
242
389
  READY_DATA: BootstrapGameData;
390
+ /** Sent by REPLs and dev tooling to reset the game with a revised puzzle string without a full reload. */
243
391
  RESET_DATA: {
244
392
  data: any;
245
393
  };
394
+ /** The player requested a fresh attempt at the same puzzle. Reset all game state and restart. */
246
395
  RETRY_PUZZLE: object;
396
+ /** The host is ready — start the game clock and begin accepting player input. */
247
397
  START_GAME: undefined;
398
+ /** The host paused the game (e.g. player switched tabs or app moved to background). Freeze input and pause the timer. */
248
399
  PAUSE_GAME: object;
400
+ /** The host resumed the game after a pause. Restore input and resume the timer. */
249
401
  RESUME_GAME: object;
402
+ /** The player changed a game setting. The payload is the full updated settings object for this game. */
250
403
  SETTINGS_UPDATE: any;
404
+ /** A key on the on-screen keyboard was tapped. `key` is the raw character token from the layout. */
405
+ KEYBOARD_KEY_PRESS: {
406
+ key: string;
407
+ };
408
+ /** The drag cursor moved to a new position while the player holds on the keyboard. Only fires when `supportsDragCursor` is `true`. */
409
+ KEYBOARD_CURSOR_CHANGE: {
410
+ position: [number, number];
411
+ };
412
+ /** The player lifted their finger, ending a drag-cursor gesture. Only fires when `supportsDragCursor` is `true`. */
413
+ KEYBOARD_CURSOR_END: object;
251
414
  };
252
415
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@puzzmo/sdk",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "Puzzmo runtime SDK for game developers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",