mcbe-ipc 3.2.1 → 3.3.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 OmniacDev
3
+ Copyright (c) 2026 OmniacDev
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -27,7 +27,7 @@ npm install mcbe-ipc
27
27
  > [!NOTE]
28
28
  > Official documentation is still in progress.
29
29
  >
30
- > For now, you can refer to the [DeepWiki page](https://deepwiki.com/OmniacDev/MCBE-IPC/).
30
+ > For now, you can [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/OmniacDev/MCBE-IPC).
31
31
  > Please note that while it is generally accurate, some of the more advanced sections may contain small inaccuracies.
32
32
 
33
33
 
package/dist/ipc.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * @license
3
3
  * MIT License
4
4
  *
5
- * Copyright (c) 2025 OmniacDev
5
+ * Copyright (c) 2026 OmniacDev
6
6
  *
7
7
  * Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  * of this software and associated documentation files (the "Software"), to deal
@@ -23,20 +23,15 @@
23
23
  * SOFTWARE.
24
24
  */
25
25
  export declare namespace PROTO {
26
- const t: unique symbol;
27
- interface Phantom<T> {
28
- readonly [t]?: T;
29
- }
30
- export interface Serializer<T> extends Phantom<T> {
26
+ interface Serializer<T> {
31
27
  serialize(value: T, stream: Buffer): Generator<void, void, void>;
32
28
  }
33
- export interface Deserializer<T> extends Phantom<T> {
29
+ interface Deserializer<T> {
34
30
  deserialize(stream: Buffer): Generator<void, T, void>;
35
31
  }
36
- export interface Serializable<T> extends Serializer<T>, Deserializer<T> {
32
+ interface Serializable<T> extends Serializer<T>, Deserializer<T> {
37
33
  }
38
- export type Infer<S> = S extends Phantom<infer T> ? T : never;
39
- export class Buffer {
34
+ class Buffer {
40
35
  private _buffer;
41
36
  private _data_view;
42
37
  private _length;
@@ -55,65 +50,68 @@ export declare namespace PROTO {
55
50
  static from_uint8array(array: Uint8Array): Buffer;
56
51
  to_uint8array(): Uint8Array;
57
52
  }
58
- export namespace MIPS {
53
+ namespace MIPS {
59
54
  function serialize(stream: PROTO.Buffer): Generator<void, string, void>;
60
55
  function deserialize(str: string): Generator<void, PROTO.Buffer, void>;
61
56
  }
62
- export const Void: PROTO.Serializable<void>;
63
- export const Null: PROTO.Serializable<null>;
64
- export const Undefined: PROTO.Serializable<undefined>;
65
- export const Int8: PROTO.Serializable<number>;
66
- export const Int16: PROTO.Serializable<number>;
67
- export const Int32: PROTO.Serializable<number>;
68
- export const UInt8: PROTO.Serializable<number>;
69
- export const UInt16: PROTO.Serializable<number>;
70
- export const UInt32: PROTO.Serializable<number>;
71
- export const UVarInt32: PROTO.Serializable<number>;
72
- export const VarInt32: PROTO.Serializable<number>;
73
- export const Float32: PROTO.Serializable<number>;
74
- export const Float64: PROTO.Serializable<number>;
75
- export const String: PROTO.Serializable<string>;
76
- export const Boolean: PROTO.Serializable<boolean>;
77
- export const UInt8Array: PROTO.Serializable<Uint8Array>;
78
- export const Date: PROTO.Serializable<Date>;
79
- export function Object<T extends object>(s: {
57
+ const Void: PROTO.Serializable<void>;
58
+ const Null: PROTO.Serializable<null>;
59
+ const Undefined: PROTO.Serializable<undefined>;
60
+ const Int8: PROTO.Serializable<number>;
61
+ const Int16: PROTO.Serializable<number>;
62
+ const Int32: PROTO.Serializable<number>;
63
+ const UInt8: PROTO.Serializable<number>;
64
+ const UInt16: PROTO.Serializable<number>;
65
+ const UInt32: PROTO.Serializable<number>;
66
+ const UVarInt32: PROTO.Serializable<number>;
67
+ const VarInt32: PROTO.Serializable<number>;
68
+ const Float32: PROTO.Serializable<number>;
69
+ const Float64: PROTO.Serializable<number>;
70
+ const String: PROTO.Serializable<string>;
71
+ const Boolean: PROTO.Serializable<boolean>;
72
+ const UInt8Array: PROTO.Serializable<Uint8Array>;
73
+ const Date: PROTO.Serializable<Date>;
74
+ function Object<T extends object>(s: {
80
75
  [K in keyof T]: PROTO.Serializable<T[K]>;
81
76
  }): PROTO.Serializable<T>;
82
- export function Array<T>(s: PROTO.Serializable<T>): PROTO.Serializable<T[]>;
83
- export function Tuple<T extends any[]>(...s: {
77
+ function Array<T>(s: PROTO.Serializable<T>): PROTO.Serializable<T[]>;
78
+ function Tuple<T extends any[]>(...s: {
84
79
  [K in keyof T]: PROTO.Serializable<T[K]>;
85
80
  }): PROTO.Serializable<T>;
86
- export function Optional<T>(s: PROTO.Serializable<T>): PROTO.Serializable<T | undefined>;
87
- export function Map<K, V>(kS: PROTO.Serializable<K>, vS: PROTO.Serializable<V>): PROTO.Serializable<Map<K, V>>;
88
- export function Set<V>(s: PROTO.Serializable<V>): PROTO.Serializable<Set<V>>;
89
- export type Endpoint = string;
90
- export type Header = {
81
+ function Optional<T>(s: PROTO.Serializable<T>): PROTO.Serializable<T | undefined>;
82
+ function Map<K, V>(kS: PROTO.Serializable<K>, vS: PROTO.Serializable<V>): PROTO.Serializable<Map<K, V>>;
83
+ function Set<V>(s: PROTO.Serializable<V>): PROTO.Serializable<Set<V>>;
84
+ }
85
+ export declare namespace NET {
86
+ type Meta = {
91
87
  guid: string;
92
- encoding: string;
93
- index: number;
94
- final: boolean;
88
+ signature: string;
95
89
  };
96
- export const Endpoint: PROTO.Serializable<Endpoint>;
97
- export const Header: PROTO.Serializable<Header>;
90
+ const Meta: PROTO.Serializable<Meta>;
91
+ export const SIGNATURE: string;
92
+ export let FRAG_MAX: number;
93
+ export function serialize(buffer: PROTO.Buffer, max_size?: number): Generator<void, string[], void>;
94
+ export function deserialize(strings: string[]): Generator<void, PROTO.Buffer, void>;
95
+ export interface EmitOptions {
96
+ metaOverride?: Partial<Meta>;
97
+ }
98
+ export function emit<S>(endpoint: string, serializer: PROTO.Serializer<S>, value: NoInfer<S>, options?: EmitOptions): Generator<void, void, void>;
99
+ export interface ListenOptions {
100
+ filter?: (meta: Meta) => boolean;
101
+ }
102
+ export function listen<D>(endpoint: string, deserializer: PROTO.Deserializer<D>, callback: (value: NoInfer<D>, meta: Meta) => Generator<void, void, void>, options?: ListenOptions): () => void;
98
103
  export {};
99
104
  }
100
- export declare namespace NET {
101
- let FRAG_MAX: number;
102
- function serialize(buffer: PROTO.Buffer, max_size?: number): Generator<void, string[], void>;
103
- function deserialize(strings: string[]): Generator<void, PROTO.Buffer, void>;
104
- function emit<S extends PROTO.Serializer<any>>(endpoint: string, serializer: S, value: PROTO.Infer<S>): Generator<void, void, void>;
105
- function listen<D extends PROTO.Deserializer<any>>(endpoint: string, deserializer: D, callback: (value: PROTO.Infer<D>) => Generator<void, void, void>): () => void;
106
- }
107
105
  export declare namespace IPC {
108
106
  /** Sends a message with `args` to `channel` */
109
- function send<S extends PROTO.Serializer<any>>(channel: string, serializer: S, value: PROTO.Infer<S>): void;
107
+ function send<S>(channel: string, serializer: PROTO.Serializer<S>, value: NoInfer<S>): void;
110
108
  /** Sends an `invoke` message through IPC, and expects a result asynchronously. */
111
- function invoke<S extends PROTO.Serializer<any>, D extends PROTO.Deserializer<any>>(channel: string, serializer: S, value: PROTO.Infer<S>, deserializer: D): Promise<PROTO.Infer<D>>;
109
+ function invoke<S, D>(channel: string, serializer: PROTO.Serializer<S>, value: NoInfer<S>, deserializer: PROTO.Deserializer<D>): Promise<NoInfer<D>>;
112
110
  /** Listens to `channel`. When a new message arrives, `listener` will be called with `listener(args)`. */
113
- function on<D extends PROTO.Deserializer<any>>(channel: string, deserializer: D, listener: (value: PROTO.Infer<D>) => void): () => void;
111
+ function on<D>(channel: string, deserializer: PROTO.Deserializer<D>, listener: (value: NoInfer<D>) => void): () => void;
114
112
  /** Listens to `channel` once. When a new message arrives, `listener` will be called with `listener(args)`, and then removed. */
115
- function once<D extends PROTO.Deserializer<any>>(channel: string, deserializer: D, listener: (value: PROTO.Infer<D>) => void): () => void;
113
+ function once<D>(channel: string, deserializer: PROTO.Deserializer<D>, listener: (value: NoInfer<D>) => void): () => void;
116
114
  /** Adds a handler for an `invoke` IPC. This handler will be called whenever `invoke(channel, ...args)` is called */
117
- function handle<D extends PROTO.Deserializer<any>, S extends PROTO.Serializer<any>>(channel: string, deserializer: D, serializer: S, listener: (value: PROTO.Infer<D>) => PROTO.Infer<S>): () => void;
115
+ function handle<D, S>(channel: string, deserializer: PROTO.Deserializer<D>, serializer: PROTO.Serializer<S>, listener: (value: NoInfer<D>) => NoInfer<S>): () => void;
118
116
  }
119
117
  export default IPC;
package/dist/ipc.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * @license
3
3
  * MIT License
4
4
  *
5
- * Copyright (c) 2025 OmniacDev
5
+ * Copyright (c) 2026 OmniacDev
6
6
  *
7
7
  * Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  * of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +23,14 @@
23
23
  * SOFTWARE.
24
24
  */
25
25
  import { ScriptEventSource, system } from '@minecraft/server';
26
+ var UTIL;
27
+ (function (UTIL) {
28
+ function generate_id() {
29
+ const r = (Math.random() * 0x100000000) >>> 0;
30
+ return r.toString(16).padStart(8, '0').toUpperCase();
31
+ }
32
+ UTIL.generate_id = generate_id;
33
+ })(UTIL || (UTIL = {}));
26
34
  export var PROTO;
27
35
  (function (PROTO) {
28
36
  class Buffer {
@@ -394,19 +402,22 @@ export var PROTO;
394
402
  };
395
403
  }
396
404
  PROTO.Set = Set;
397
- PROTO.Endpoint = PROTO.String;
398
- PROTO.Header = PROTO.Object({
405
+ })(PROTO || (PROTO = {}));
406
+ export var NET;
407
+ (function (NET) {
408
+ const Endpoint = PROTO.String;
409
+ const Meta = PROTO.Object({
399
410
  guid: PROTO.String,
400
- encoding: PROTO.String,
411
+ signature: PROTO.String
412
+ });
413
+ const Header = PROTO.Object({
414
+ meta: Meta,
401
415
  index: PROTO.UVarInt32,
402
416
  final: PROTO.Boolean
403
417
  });
404
- })(PROTO || (PROTO = {}));
405
- export var NET;
406
- (function (NET) {
418
+ const LISTENERS = new Map();
419
+ NET.SIGNATURE = 'mcbe-ipc:v3';
407
420
  NET.FRAG_MAX = 2048;
408
- const ENCODING = 'mcbe-ipc:v3';
409
- const ENDPOINTS = new Map();
410
421
  function* serialize(buffer, max_size = Infinity) {
411
422
  const uint8array = buffer.to_uint8array();
412
423
  const result = [];
@@ -464,15 +475,15 @@ export var NET;
464
475
  return;
465
476
  const [serialized_endpoint, serialized_header] = event.id.split(':');
466
477
  const endpoint_stream = yield* PROTO.MIPS.deserialize(serialized_endpoint);
467
- const endpoint = yield* PROTO.Endpoint.deserialize(endpoint_stream);
468
- const listeners = ENDPOINTS.get(endpoint);
478
+ const endpoint = yield* Endpoint.deserialize(endpoint_stream);
479
+ const listeners = LISTENERS.get(endpoint);
469
480
  if (listeners !== undefined) {
470
481
  const header_stream = yield* PROTO.MIPS.deserialize(serialized_header);
471
- const header = yield* PROTO.Header.deserialize(header_stream);
482
+ const header = yield* Header.deserialize(header_stream);
472
483
  const errors = [];
473
- for (let i = 0; i < listeners.length; i++) {
484
+ for (const listener of [...listeners]) {
474
485
  try {
475
- yield* listeners[i](header, event.message);
486
+ yield* listener(header, event.message);
476
487
  }
477
488
  catch (e) {
478
489
  errors.push(e);
@@ -483,11 +494,11 @@ export var NET;
483
494
  }
484
495
  })());
485
496
  });
486
- function create_listener(endpoint, listener) {
487
- let listeners = ENDPOINTS.get(endpoint);
488
- if (!listeners) {
497
+ function register(endpoint, listener) {
498
+ let listeners = LISTENERS.get(endpoint);
499
+ if (listeners === undefined) {
489
500
  listeners = new Array();
490
- ENDPOINTS.set(endpoint, listeners);
501
+ LISTENERS.set(endpoint, listeners);
491
502
  }
492
503
  listeners.push(listener);
493
504
  return () => {
@@ -495,56 +506,61 @@ export var NET;
495
506
  if (idx !== -1)
496
507
  listeners.splice(idx, 1);
497
508
  if (listeners.length === 0) {
498
- ENDPOINTS.delete(endpoint);
509
+ LISTENERS.delete(endpoint);
499
510
  }
500
511
  };
501
512
  }
502
- function generate_id() {
503
- const r = (Math.random() * 0x100000000) >>> 0;
504
- return ((r & 0xff).toString(16).padStart(2, '0') +
505
- ((r >> 8) & 0xff).toString(16).padStart(2, '0') +
506
- ((r >> 16) & 0xff).toString(16).padStart(2, '0') +
507
- ((r >> 24) & 0xff).toString(16).padStart(2, '0')).toUpperCase();
508
- }
509
- function* emit(endpoint, serializer, value) {
510
- const guid = generate_id();
513
+ function* emit(endpoint, serializer, value, options) {
514
+ const guid = options?.metaOverride?.guid ?? UTIL.generate_id();
515
+ const signature = options?.metaOverride?.signature ?? NET.SIGNATURE;
511
516
  const endpoint_stream = new PROTO.Buffer();
512
- yield* PROTO.Endpoint.serialize(endpoint, endpoint_stream);
517
+ yield* Endpoint.serialize(endpoint, endpoint_stream);
513
518
  const serialized_endpoint = yield* PROTO.MIPS.serialize(endpoint_stream);
514
519
  const packet_stream = new PROTO.Buffer();
515
520
  yield* serializer.serialize(value, packet_stream);
516
521
  const serialized_packets = yield* serialize(packet_stream, NET.FRAG_MAX);
517
522
  for (let i = 0; i < serialized_packets.length; i++) {
518
523
  const serialized_packet = serialized_packets[i];
519
- const header = { guid, encoding: ENCODING, index: i, final: i === serialized_packets.length - 1 };
524
+ const header = {
525
+ meta: { guid, signature },
526
+ index: i,
527
+ final: i === serialized_packets.length - 1
528
+ };
520
529
  const header_stream = new PROTO.Buffer();
521
- yield* PROTO.Header.serialize(header, header_stream);
530
+ yield* Header.serialize(header, header_stream);
522
531
  const serialized_header = yield* PROTO.MIPS.serialize(header_stream);
523
532
  system.sendScriptEvent(`${serialized_endpoint}:${serialized_header}`, serialized_packet);
524
533
  }
525
534
  }
526
535
  NET.emit = emit;
527
- function listen(endpoint, deserializer, callback) {
536
+ function listen(endpoint, deserializer, callback, options) {
528
537
  const buffer = new Map();
529
- const listener = function* (payload, serialized_packet) {
530
- let fragment = buffer.get(payload.guid);
531
- if (!fragment) {
532
- fragment = { size: -1, serialized_packets: [], data_size: 0 };
533
- buffer.set(payload.guid, fragment);
538
+ const listener = function* (header, fragment) {
539
+ let packet = buffer.get(header.meta.guid);
540
+ if (packet === undefined) {
541
+ if (options?.filter?.(header.meta) === false)
542
+ return;
543
+ packet = { size: -1, fragments: [], received: 0 };
544
+ buffer.set(header.meta.guid, packet);
534
545
  }
535
- if (payload.final) {
536
- fragment.size = payload.index + 1;
546
+ if (header.final) {
547
+ packet.size = header.index + 1;
537
548
  }
538
- fragment.serialized_packets[payload.index] = serialized_packet;
539
- fragment.data_size += payload.index + 1;
540
- if (fragment.size !== -1 && fragment.data_size === (fragment.size * (fragment.size + 1)) / 2) {
541
- const stream = yield* deserialize(fragment.serialized_packets);
549
+ if (packet.fragments[header.index] === undefined) {
550
+ packet.fragments[header.index] = fragment;
551
+ packet.received++;
552
+ }
553
+ else {
554
+ throw new Error(`received duplicate fragment ${header.index} for packet ${header.meta.guid}`);
555
+ }
556
+ if (packet.size !== -1 && packet.size === packet.received) {
557
+ const stream = yield* deserialize(packet.fragments);
542
558
  const value = yield* deserializer.deserialize(stream);
543
- yield* callback(value);
544
- buffer.delete(payload.guid);
559
+ yield* callback(value, header.meta);
560
+ buffer.delete(header.meta.guid);
545
561
  }
546
562
  };
547
- return create_listener(endpoint, listener);
563
+ return register(endpoint, listener);
548
564
  }
549
565
  NET.listen = listen;
550
566
  })(NET || (NET = {}));
@@ -557,12 +573,22 @@ export var IPC;
557
573
  IPC.send = send;
558
574
  /** Sends an `invoke` message through IPC, and expects a result asynchronously. */
559
575
  function invoke(channel, serializer, value, deserializer) {
576
+ const id = UTIL.generate_id();
560
577
  return new Promise(resolve => {
561
- const terminate = NET.listen(`ipc:${channel}:handle`, deserializer, function* (value) {
578
+ const terminate = NET.listen(`ipc:${channel}:handle`, deserializer, function* (value, meta) {
579
+ if (meta.signature.includes(`+correlation`) && meta.guid !== id)
580
+ return;
562
581
  resolve(value);
563
582
  terminate();
583
+ }, {
584
+ filter: meta => !meta.signature.includes(`+correlation`) || meta.guid === id
564
585
  });
565
- system.runJob(NET.emit(`ipc:${channel}:invoke`, serializer, value));
586
+ system.runJob(NET.emit(`ipc:${channel}:invoke`, serializer, value, {
587
+ metaOverride: {
588
+ guid: id,
589
+ signature: `${NET.SIGNATURE}+correlation`
590
+ }
591
+ }));
566
592
  });
567
593
  }
568
594
  IPC.invoke = invoke;
@@ -584,9 +610,16 @@ export var IPC;
584
610
  IPC.once = once;
585
611
  /** Adds a handler for an `invoke` IPC. This handler will be called whenever `invoke(channel, ...args)` is called */
586
612
  function handle(channel, deserializer, serializer, listener) {
587
- return NET.listen(`ipc:${channel}:invoke`, deserializer, function* (value) {
613
+ return NET.listen(`ipc:${channel}:invoke`, deserializer, function* (value, meta) {
588
614
  const result = listener(value);
589
- yield* NET.emit(`ipc:${channel}:handle`, serializer, result);
615
+ yield* NET.emit(`ipc:${channel}:handle`, serializer, result, {
616
+ metaOverride: meta.signature.includes(`+correlation`)
617
+ ? {
618
+ guid: meta.guid,
619
+ signature: `${NET.SIGNATURE}+correlation`
620
+ }
621
+ : undefined
622
+ });
590
623
  });
591
624
  }
592
625
  IPC.handle = handle;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "author": "OmniacDev",
4
4
  "description": "IPC system for MCBE Script API projects",
5
5
  "license": "MIT",
6
- "version": "3.2.1",
6
+ "version": "3.3.1",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/OmniacDev/MCBE-IPC.git"