@rpgm-tools/neo-angband-mod-sdk 1.2.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/manifest.ts CHANGED
@@ -309,6 +309,9 @@ export const DEFAULT_PACK_GROUP = "content";
309
309
  */
310
310
  export type Capability = string;
311
311
 
312
+ /** How code declared by a plugin-facet pack is executed. */
313
+ export type PluginRuntime = "in-process" | "worker";
314
+
312
315
  /**
313
316
  * One graphics mode a `tiles`-facet pack contributes.
314
317
  *
@@ -479,6 +482,16 @@ export interface PackManifest {
479
482
  * exist yet.
480
483
  */
481
484
  modApi?: number;
485
+ /**
486
+ * The execution ABI selected by a code pack. API 1 keeps the historical
487
+ * in-process `plugin.js` entry; API 2 requires the isolated worker runtime.
488
+ */
489
+ runtime?: PluginRuntime;
490
+ /**
491
+ * The module imported by the host-owned API-2 Worker bootstrap. This is a
492
+ * mod-relative file, never a host module name or URL.
493
+ */
494
+ workerEntry?: string;
482
495
  /**
483
496
  * Player-toggleable flags this pack owns (see PackRule). The bundled qol /
484
497
  * bug-fixes mods use this to declare their fixes/tweaks for the in-app "Fixes
@@ -683,6 +696,32 @@ export function validateManifest(value: unknown): PackManifest {
683
696
  );
684
697
  }
685
698
  }
699
+ if (m["runtime"] !== undefined && m["runtime"] !== "in-process" && m["runtime"] !== "worker") {
700
+ throw new ManifestError(`manifest ${id}: runtime must be "in-process" or "worker"`);
701
+ }
702
+ if (m["workerEntry"] !== undefined) {
703
+ const entry = m["workerEntry"];
704
+ if (
705
+ typeof entry !== "string" ||
706
+ entry.length === 0 ||
707
+ entry.startsWith("/") ||
708
+ entry.includes("\\") ||
709
+ entry.split("/").some((part) => part === "" || part === "." || part === "..")
710
+ ) {
711
+ throw new ManifestError(`manifest ${id}: workerEntry must be a non-empty relative file path`);
712
+ }
713
+ }
714
+ if (m["modApi"] === 2) {
715
+ if (m["runtime"] !== "worker") {
716
+ throw new ManifestError(`manifest ${id}: modApi 2 requires runtime "worker"`);
717
+ }
718
+ if (typeof m["workerEntry"] !== "string") {
719
+ throw new ManifestError(`manifest ${id}: modApi 2 requires workerEntry`);
720
+ }
721
+ }
722
+ if (m["runtime"] === "worker" && m["modApi"] !== 2) {
723
+ throw new ManifestError(`manifest ${id}: runtime "worker" requires modApi 2`);
724
+ }
686
725
  if (
687
726
  m["nondeterministic"] !== undefined &&
688
727
  typeof m["nondeterministic"] !== "boolean"