@idosgames/module-sdk 0.9.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- 'use strict';var x=/^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*@[1-9]\d*$/;function S(e){return typeof e=="string"&&x.test(e)}function T(e){let t=e.indexOf(":");return t<0?"":e.slice(0,t)}var c=/^(string|number|boolean)(\[\])?(\?)?$/;function u(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function l(e,t){return e==="number"?typeof t=="number"&&Number.isFinite(t):typeof t===e}function f(e,t,r){if(!u(t))return `${r||"payload"} must be an object`;for(let[n,o]of Object.entries(e)){let i=r?`${r}.${n}`:n,a=t[n];if(typeof o!="string"){let p=f(o,a,i);if(p)return p;continue}let d=c.exec(o);if(!d)return `${i}: invalid descriptor "${o}"`;let[,s="",g,m]=d;if(a===void 0){if(m)continue;return `${i} is missing`}if(g){if(!Array.isArray(a))return `${i} must be ${s}[]`;if(!a.every(p=>l(s,p)))return `${i} must contain only ${s} values`;continue}if(!l(s,a))return `${i} must be a ${s}`}return null}function y(e,t){for(let[r,n]of Object.entries(e)){let o=t?`${t}.${r}`:r;if(typeof n=="string"){if(!c.test(n))throw new Error(`shape(): field "${o}" has invalid type "${n}" \u2014 use "string" | "number" | "boolean", optionally with "[]" and/or a trailing "?"`)}else if(u(n))y(n,o);else throw new Error(`shape(): field "${o}" must be a type string or an object`)}}function h(e){return y(e,""),{descriptor:e,check:t=>f(e,t,"")}}function v(e,t){if(!S(e))throw new Error(`defineTopic(): "${e}" is not a valid topic name \u2014 expected "<module-id>:<event>@<major>", e.g. "idle-rpg:character-upgraded@1"`);return {name:e,shape:t}}var b={modeChanged:v("host:mode-changed@1",h({from:"string?",to:"string"}))};var M=["currency-bar","wallet","status","account","menu","modes"];function R(e){return typeof e=="string"&&M.includes(e)}function D(e){return e}exports.SHARED_UI_ROLES=M;exports.TOPIC_NAME_RE=x;exports.defineModule=D;exports.defineTopic=v;exports.hostTopics=b;exports.isSharedUiRole=R;exports.isTopicName=S;exports.shape=h;exports.topicNamespace=T;
1
+ 'use strict';var x=/^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*@[1-9]\d*$/;function S(e){return typeof e=="string"&&x.test(e)}function b(e){let t=e.indexOf(":");return t<0?"":e.slice(0,t)}var c=/^(string|number|boolean)(\[\])?(\?)?$/;function u(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function l(e,t){return e==="number"?typeof t=="number"&&Number.isFinite(t):typeof t===e}function f(e,t,r){if(!u(t))return `${r||"payload"} must be an object`;for(let[n,o]of Object.entries(e)){let i=r?`${r}.${n}`:n,a=t[n];if(typeof o!="string"){let p=f(o,a,i);if(p)return p;continue}let d=c.exec(o);if(!d)return `${i}: invalid descriptor "${o}"`;let[,s="",g,m]=d;if(a===void 0){if(m)continue;return `${i} is missing`}if(g){if(!Array.isArray(a))return `${i} must be ${s}[]`;if(!a.every(p=>l(s,p)))return `${i} must contain only ${s} values`;continue}if(!l(s,a))return `${i} must be a ${s}`}return null}function y(e,t){for(let[r,n]of Object.entries(e)){let o=t?`${t}.${r}`:r;if(typeof n=="string"){if(!c.test(n))throw new Error(`shape(): field "${o}" has invalid type "${n}" \u2014 use "string" | "number" | "boolean", optionally with "[]" and/or a trailing "?"`)}else if(u(n))y(n,o);else throw new Error(`shape(): field "${o}" must be a type string or an object`)}}function h(e){return y(e,""),{descriptor:e,check:t=>f(e,t,"")}}function v(e,t){if(!S(e))throw new Error(`defineTopic(): "${e}" is not a valid topic name \u2014 expected "<module-id>:<event>@<major>", e.g. "idle-rpg:character-upgraded@1"`);return {name:e,shape:t}}var T={modeChanged:v("host:mode-changed@1",h({from:"string?",to:"string"}))};var M=["currency-bar","wallet","status","account","menu","modes"];function R(e){return typeof e=="string"&&M.includes(e)}function D(e){return e}exports.SHARED_UI_ROLES=M;exports.TOPIC_NAME_RE=x;exports.defineModule=D;exports.defineTopic=v;exports.hostTopics=T;exports.isSharedUiRole=R;exports.isTopicName=S;exports.shape=h;exports.topicNamespace=b;
package/dist/index.d.cts CHANGED
@@ -594,6 +594,19 @@ interface ModuleContext {
594
594
  registerPanel(panel: UiPanel): void;
595
595
  /** Register a nav / mode entry so the player can switch to this module. */
596
596
  registerRoute(entry: RouteEntry): void;
597
+ /**
598
+ * Runs `run` now and keeps what it started alive until the module is torn down (logout, a new
599
+ * login): the function it returns is called then. Use it for background work that needs no screen -
600
+ * keeping a menu badge in step with the player's state (`client.on("user:anyUpdated", …)` returns
601
+ * its unsubscribe, return that), a timer, a document listener. Do not mount a hidden React panel
602
+ * for this.
603
+ */
604
+ effect(run: () => void | (() => void)): void;
605
+ /**
606
+ * Calls `run` now and then every `ms` milliseconds until the module is torn down - the polling
607
+ * form of `effect`, with the timer cleared for you.
608
+ */
609
+ every(ms: number, run: () => void): void;
597
610
  /**
598
611
  * Content types other modules can publish and open (see `ContentTypeHandler`). A game registers
599
612
  * its type here; the Workshop module reads the registry — neither imports the other.
@@ -773,6 +786,13 @@ interface RouteEntry {
773
786
  /** Optional icon (emoji or short glyph the host nav renders). */
774
787
  icon?: string;
775
788
  order?: number;
789
+ /**
790
+ * A game that lives INSIDE the lobby: the base keeps the lobby's balances on top and its tabs at
791
+ * the bottom around it, "Play" is this game, and the app starts in it after sign-in (idle-rpg).
792
+ * Without it (the default) a game takes the whole screen, launched by "Play" in the lobby, with a
793
+ * small button back (voxelcraft, board-game).
794
+ */
795
+ inLobby?: boolean;
776
796
  }
777
797
  /** A mode of the app as every module sees it (`ctx.modes`): a registered route plus its owner. */
778
798
  interface ModeEntry {
@@ -785,6 +805,8 @@ interface ModeEntry {
785
805
  moduleId: string;
786
806
  /** That module's `meta.type` — a lobby offers "Play" for `game` modes. */
787
807
  moduleType: ModuleType;
808
+ /** The route's `inLobby`: the game sits inside the lobby rather than taking the whole screen. */
809
+ inLobby?: boolean;
788
810
  }
789
811
  /** `ctx.modes` — the modes of the app, live. Switch with `ctx.navigate(id)`. */
790
812
  interface ModeRegistry {
package/dist/index.d.ts CHANGED
@@ -594,6 +594,19 @@ interface ModuleContext {
594
594
  registerPanel(panel: UiPanel): void;
595
595
  /** Register a nav / mode entry so the player can switch to this module. */
596
596
  registerRoute(entry: RouteEntry): void;
597
+ /**
598
+ * Runs `run` now and keeps what it started alive until the module is torn down (logout, a new
599
+ * login): the function it returns is called then. Use it for background work that needs no screen -
600
+ * keeping a menu badge in step with the player's state (`client.on("user:anyUpdated", …)` returns
601
+ * its unsubscribe, return that), a timer, a document listener. Do not mount a hidden React panel
602
+ * for this.
603
+ */
604
+ effect(run: () => void | (() => void)): void;
605
+ /**
606
+ * Calls `run` now and then every `ms` milliseconds until the module is torn down - the polling
607
+ * form of `effect`, with the timer cleared for you.
608
+ */
609
+ every(ms: number, run: () => void): void;
597
610
  /**
598
611
  * Content types other modules can publish and open (see `ContentTypeHandler`). A game registers
599
612
  * its type here; the Workshop module reads the registry — neither imports the other.
@@ -773,6 +786,13 @@ interface RouteEntry {
773
786
  /** Optional icon (emoji or short glyph the host nav renders). */
774
787
  icon?: string;
775
788
  order?: number;
789
+ /**
790
+ * A game that lives INSIDE the lobby: the base keeps the lobby's balances on top and its tabs at
791
+ * the bottom around it, "Play" is this game, and the app starts in it after sign-in (idle-rpg).
792
+ * Without it (the default) a game takes the whole screen, launched by "Play" in the lobby, with a
793
+ * small button back (voxelcraft, board-game).
794
+ */
795
+ inLobby?: boolean;
776
796
  }
777
797
  /** A mode of the app as every module sees it (`ctx.modes`): a registered route plus its owner. */
778
798
  interface ModeEntry {
@@ -785,6 +805,8 @@ interface ModeEntry {
785
805
  moduleId: string;
786
806
  /** That module's `meta.type` — a lobby offers "Play" for `game` modes. */
787
807
  moduleType: ModuleType;
808
+ /** The route's `inLobby`: the game sits inside the lobby rather than taking the whole screen. */
809
+ inLobby?: boolean;
788
810
  }
789
811
  /** `ctx.modes` — the modes of the app, live. Switch with `ctx.navigate(id)`. */
790
812
  interface ModeRegistry {
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var x=/^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*@[1-9]\d*$/;function S(e){return typeof e=="string"&&x.test(e)}function T(e){let t=e.indexOf(":");return t<0?"":e.slice(0,t)}var c=/^(string|number|boolean)(\[\])?(\?)?$/;function u(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function l(e,t){return e==="number"?typeof t=="number"&&Number.isFinite(t):typeof t===e}function f(e,t,r){if(!u(t))return `${r||"payload"} must be an object`;for(let[n,o]of Object.entries(e)){let i=r?`${r}.${n}`:n,a=t[n];if(typeof o!="string"){let p=f(o,a,i);if(p)return p;continue}let d=c.exec(o);if(!d)return `${i}: invalid descriptor "${o}"`;let[,s="",g,m]=d;if(a===void 0){if(m)continue;return `${i} is missing`}if(g){if(!Array.isArray(a))return `${i} must be ${s}[]`;if(!a.every(p=>l(s,p)))return `${i} must contain only ${s} values`;continue}if(!l(s,a))return `${i} must be a ${s}`}return null}function y(e,t){for(let[r,n]of Object.entries(e)){let o=t?`${t}.${r}`:r;if(typeof n=="string"){if(!c.test(n))throw new Error(`shape(): field "${o}" has invalid type "${n}" \u2014 use "string" | "number" | "boolean", optionally with "[]" and/or a trailing "?"`)}else if(u(n))y(n,o);else throw new Error(`shape(): field "${o}" must be a type string or an object`)}}function h(e){return y(e,""),{descriptor:e,check:t=>f(e,t,"")}}function v(e,t){if(!S(e))throw new Error(`defineTopic(): "${e}" is not a valid topic name \u2014 expected "<module-id>:<event>@<major>", e.g. "idle-rpg:character-upgraded@1"`);return {name:e,shape:t}}var b={modeChanged:v("host:mode-changed@1",h({from:"string?",to:"string"}))};var M=["currency-bar","wallet","status","account","menu","modes"];function R(e){return typeof e=="string"&&M.includes(e)}function D(e){return e}export{M as SHARED_UI_ROLES,x as TOPIC_NAME_RE,D as defineModule,v as defineTopic,b as hostTopics,R as isSharedUiRole,S as isTopicName,h as shape,T as topicNamespace};
1
+ var x=/^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*@[1-9]\d*$/;function S(e){return typeof e=="string"&&x.test(e)}function b(e){let t=e.indexOf(":");return t<0?"":e.slice(0,t)}var c=/^(string|number|boolean)(\[\])?(\?)?$/;function u(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function l(e,t){return e==="number"?typeof t=="number"&&Number.isFinite(t):typeof t===e}function f(e,t,r){if(!u(t))return `${r||"payload"} must be an object`;for(let[n,o]of Object.entries(e)){let i=r?`${r}.${n}`:n,a=t[n];if(typeof o!="string"){let p=f(o,a,i);if(p)return p;continue}let d=c.exec(o);if(!d)return `${i}: invalid descriptor "${o}"`;let[,s="",g,m]=d;if(a===void 0){if(m)continue;return `${i} is missing`}if(g){if(!Array.isArray(a))return `${i} must be ${s}[]`;if(!a.every(p=>l(s,p)))return `${i} must contain only ${s} values`;continue}if(!l(s,a))return `${i} must be a ${s}`}return null}function y(e,t){for(let[r,n]of Object.entries(e)){let o=t?`${t}.${r}`:r;if(typeof n=="string"){if(!c.test(n))throw new Error(`shape(): field "${o}" has invalid type "${n}" \u2014 use "string" | "number" | "boolean", optionally with "[]" and/or a trailing "?"`)}else if(u(n))y(n,o);else throw new Error(`shape(): field "${o}" must be a type string or an object`)}}function h(e){return y(e,""),{descriptor:e,check:t=>f(e,t,"")}}function v(e,t){if(!S(e))throw new Error(`defineTopic(): "${e}" is not a valid topic name \u2014 expected "<module-id>:<event>@<major>", e.g. "idle-rpg:character-upgraded@1"`);return {name:e,shape:t}}var T={modeChanged:v("host:mode-changed@1",h({from:"string?",to:"string"}))};var M=["currency-bar","wallet","status","account","menu","modes"];function R(e){return typeof e=="string"&&M.includes(e)}function D(e){return e}export{M as SHARED_UI_ROLES,x as TOPIC_NAME_RE,D as defineModule,v as defineTopic,T as hostTopics,R as isSharedUiRole,S as isTopicName,h as shape,b as topicNamespace};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idosgames/module-sdk",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "description": "The composable-module contract for the iDosGames host shell: Module / ModuleContext types plus tiny authoring helpers. Framework-neutral at runtime — a module can be a game (Three/Phaser), a plain app, or an AI app.",
5
5
  "type": "module",
6
6
  "license": "MIT",