kustom-mc 0.1.2 → 0.1.4

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/runtime.d.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * plain objects with __type property injected.
9
9
  */
10
10
  import './types/globals.js';
11
- import type { ScriptConfig, ExportedScript, PropSchema, EventSchema, EmptyEventSchema, BlockConfig, BlockDefinition, ItemConfig, ItemDefinition, ScreenConstructor, ContainerConstructor, ElementFactory, ScriptableLocationFactory, PropsAPI, CellStateUtils } from './types/index.js';
11
+ import type { ScriptConfig, ScriptConfigWithMethods, ExportedScript, PropSchema, EventSchema, EmptyEventSchema, BlockConfig, BlockDefinition, ItemConfig, ItemDefinition, ScreenConstructor, ContainerConstructor, ElementFactory, ScriptableLocationFactory, PropsAPI, CellStateUtils, MethodMap } from './types/index.js';
12
12
  /**
13
13
  * Screen constructor - create new screens for GUIs.
14
14
  * Actual value is injected by Java at runtime.
@@ -59,13 +59,31 @@ export declare const ScriptableLocation: ScriptableLocationFactory;
59
59
  * onSuccess: Props.Boolean(),
60
60
  * onError: Props.String(),
61
61
  * },
62
- * run({ process, props }) {
62
+ * methods: {
63
+ * greet({ executor, props }) {
64
+ * executor.asPlayer()?.sendMessage(props.message);
65
+ * },
66
+ * },
67
+ * run({ process, props, methods }) {
63
68
  * const player = process.getPlayer(props.player);
64
69
  * player.sendMessage(props.message);
70
+ * methods.greet(); // ctx auto-injected!
65
71
  * process.emit("onSuccess", true); // Typed!
66
72
  * }
67
73
  * });
68
74
  */
75
+ /**
76
+ * Define a kustom script with type safety and strongly-typed methods.
77
+ *
78
+ * Overload 1: Script WITH methods — M is inferred from the methods object,
79
+ * providing full autocomplete and type safety for ctx.methods.
80
+ */
81
+ export declare function defineScript<P extends PropSchema, E extends EventSchema, M extends MethodMap<P, E>>(config: ScriptConfigWithMethods<P, E, M>): ExportedScript<P, E>;
82
+ /**
83
+ * Define a kustom script with type safety.
84
+ *
85
+ * Overload 2: Script WITHOUT methods — simpler signature, backward compatible.
86
+ */
69
87
  export declare function defineScript<P extends PropSchema = Record<string, never>, E extends EventSchema = EmptyEventSchema>(config: ScriptConfig<P, E>): ExportedScript<P, E>;
70
88
  /**
71
89
  * Define a custom block with type safety.
@@ -113,4 +131,4 @@ export declare function defineBlock(config: BlockConfig): BlockDefinition;
113
131
  * });
114
132
  */
115
133
  export declare function defineItem(config: ItemConfig): ItemDefinition;
116
- export type { ScriptConfig, ScriptDefinition, ExportedScript, ScriptContext, PropSchema, PropAPI, InferProps, PropsAPI, EventSchema, EmptyEventSchema, InferEventPayload, ScriptModule, ScriptProcess, TypedScriptProcess, InferScriptModule, McModuleAPI, TypedMcModuleAPI, ProcessExecutorAPI, CameraAPI, SessionAPI, ChatGUIAPI, CommandManager, BetterModelEntityAPI, ShaperAPI, ItemAPI, DefinitionBuilder, ScriptablePlayer, BlockConfig, BlockDefinition, BlockClickEvent, BlockBreakEvent, BlockPlaceEvent, ItemConfig, ItemDefinition, ScreenConstructor, ContainerConstructor, ElementFactory, ScriptableLocationFactory, CellStateUtils, } from './types/index.js';
134
+ export type { ScriptConfig, ScriptDefinition, ExportedScript, BaseScriptContext, ScriptContext, PropSchema, PropAPI, InferProps, PropsAPI, WrappedMethods, MethodMap, EventSchema, EmptyEventSchema, InferEventPayload, ScriptModule, ScriptProcess, TypedScriptProcess, InferScriptModule, McModuleAPI, TypedMcModuleAPI, ProcessExecutorAPI, CameraAPI, SessionAPI, ChatGUIAPI, CommandManager, BetterModelEntityAPI, ShaperAPI, ItemAPI, DefinitionBuilder, ScriptablePlayer, BlockConfig, BlockDefinition, BlockClickEvent, BlockBreakEvent, BlockPlaceEvent, ItemConfig, ItemDefinition, ScreenConstructor, ContainerConstructor, ElementFactory, ScriptableLocationFactory, CellStateUtils, } from './types/index.js';
package/dist/runtime.js CHANGED
@@ -9,36 +9,11 @@
9
9
  */
10
10
  // Import globals for side effects - makes console, setTimeout, etc. available
11
11
  import './types/globals.js';
12
- /**
13
- * Define a kustom script with type safety.
14
- *
15
- * This is a type-only helper that returns its input unchanged.
16
- * The Java ProcessManager extracts the `run` function and calls it
17
- * with the ScriptContext.
18
- *
19
- * @example
20
- * import { defineScript, Props } from 'kustom-mc';
21
- *
22
- * export default defineScript({
23
- * props: {
24
- * player: Props.String(),
25
- * message: Props.String("Hello!"),
26
- * },
27
- * events: {
28
- * onSuccess: Props.Boolean(),
29
- * onError: Props.String(),
30
- * },
31
- * run({ process, props }) {
32
- * const player = process.getPlayer(props.player);
33
- * player.sendMessage(props.message);
34
- * process.emit("onSuccess", true); // Typed!
35
- * }
36
- * });
37
- */
12
+ // Implementation
38
13
  export function defineScript(config) {
39
14
  // Simply return the config - the Java side will handle execution
40
15
  // The return type is ExportedScript which combines:
41
- // - Definition metadata (props, events, __type) for the Java runtime
16
+ // - Definition metadata (props, events, methods, __type) for the Java runtime
42
17
  // - ScriptModule interface with .run(props) method for TypeScript imports
43
18
  return config;
44
19
  }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Debug: Check what M resolves to
3
+ */
4
+ export {};
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Debug: Check what M resolves to
3
+ */
4
+ import { defineScript } from '../../runtime.js';
5
+ const Props = {
6
+ String: (defaultValue) => ({ __brand: 'StringPropAPI', defaultValue }),
7
+ };
8
+ const result = defineScript({
9
+ props: {
10
+ message: Props.String("Hello!"),
11
+ },
12
+ methods: {
13
+ toto({ executor }) {
14
+ executor.asPlayer()?.sendMessage("toto!");
15
+ },
16
+ },
17
+ run({ methods }) {
18
+ // Let's see what type methods is
19
+ const m = methods;
20
+ const _check = m;
21
+ console.log(_check);
22
+ },
23
+ });
24
+ const _r = result;
25
+ console.log(_r);
@@ -0,0 +1,27 @@
1
+ /**
2
+ * DX test for strongly-typed defineScript methods.
3
+ *
4
+ * This simulates the EXACT user experience — calling defineScript()
5
+ * with methods and verifying autocomplete/type safety.
6
+ *
7
+ * Run: npx tsc --noEmit
8
+ * If this file compiles, the DX is correct.
9
+ */
10
+ declare const _default: import("../index.js").ExportedScript<{
11
+ message: {
12
+ __brand: "StringPropAPI";
13
+ defaultValue: string | undefined;
14
+ };
15
+ count: {
16
+ __brand: "NumberPropAPI";
17
+ defaultValue: number | undefined;
18
+ };
19
+ }, import("../index.js").EventSchema>;
20
+ export default _default;
21
+ export declare const noMethodsScript: import("../index.js").ExportedScript<{
22
+ name: {
23
+ __brand: "StringPropAPI";
24
+ defaultValue: string | undefined;
25
+ };
26
+ }, import("../index.js").EmptyEventSchema>;
27
+ export declare const bareScript: import("../index.js").ExportedScript<Record<string, never>, import("../index.js").EmptyEventSchema>;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * DX test for strongly-typed defineScript methods.
3
+ *
4
+ * This simulates the EXACT user experience — calling defineScript()
5
+ * with methods and verifying autocomplete/type safety.
6
+ *
7
+ * Run: npx tsc --noEmit
8
+ * If this file compiles, the DX is correct.
9
+ */
10
+ import { defineScript } from '../../runtime.js';
11
+ // Simulate Props (these are runtime-injected, so we cast)
12
+ const Props = {
13
+ String: (defaultValue) => ({ __brand: 'StringPropAPI', defaultValue }),
14
+ Number: (defaultValue) => ({ __brand: 'NumberPropAPI', defaultValue }),
15
+ Boolean: (defaultValue) => ({ __brand: 'BooleanPropAPI', defaultValue }),
16
+ };
17
+ // ============================================
18
+ // Test: Full DX with methods
19
+ // ============================================
20
+ export default defineScript({
21
+ props: {
22
+ message: Props.String("Hello!"),
23
+ count: Props.Number(5),
24
+ },
25
+ methods: {
26
+ toto({ executor }) {
27
+ // ✅ executor is typed as ProcessExecutorAPI
28
+ executor.asPlayer()?.sendMessage("toto!");
29
+ },
30
+ greet({ executor, props }) {
31
+ // ✅ props is typed: props.message is string, props.count is number
32
+ const _msg = props.message;
33
+ const _cnt = props.count;
34
+ // Note: methods receive BaseScriptContext (no `methods` field)
35
+ // to avoid circular generic inference. Only run() gets methods.
36
+ executor.asPlayer()?.sendMessage("greet!");
37
+ },
38
+ doSomething({ executor }) {
39
+ // ✅ Methods receive BaseScriptContext with all subsystems
40
+ executor.asPlayer()?.sendMessage("doSomething!");
41
+ },
42
+ },
43
+ run({ executor, props, methods }) {
44
+ // ✅ props is typed
45
+ const _msg = props.message;
46
+ const _cnt = props.count;
47
+ // ✅ methods are typed with autocomplete
48
+ methods.toto();
49
+ methods.greet();
50
+ methods.doSomething();
51
+ // ✅ executor is typed
52
+ executor.asPlayer()?.sendMessage(props.message);
53
+ },
54
+ });
55
+ // ============================================
56
+ // Test: Script without methods (backward compat)
57
+ // ============================================
58
+ export const noMethodsScript = defineScript({
59
+ props: {
60
+ name: Props.String("World"),
61
+ },
62
+ run({ props }) {
63
+ // ✅ props is typed
64
+ const _name = props.name;
65
+ console.log(_name);
66
+ },
67
+ });
68
+ // ============================================
69
+ // Test: Script with no props and no methods
70
+ // ============================================
71
+ export const bareScript = defineScript({
72
+ run() {
73
+ // ✅ Compiles fine with no props/methods
74
+ console.log("bare script");
75
+ },
76
+ });
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Negative type test for strongly-typed defineScript methods.
3
+ *
4
+ * Uses @ts-expect-error to verify that invalid method calls
5
+ * produce type errors. If a @ts-expect-error line does NOT
6
+ * produce an error, tsc will report "Unused '@ts-expect-error' directive".
7
+ *
8
+ * Run: npx tsc --noEmit
9
+ */
10
+ declare const _default: import("../index.js").ExportedScript<{
11
+ message: {
12
+ __brand: "StringPropAPI";
13
+ defaultValue: string | undefined;
14
+ };
15
+ }, import("../index.js").EventSchema>;
16
+ export default _default;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Negative type test for strongly-typed defineScript methods.
3
+ *
4
+ * Uses @ts-expect-error to verify that invalid method calls
5
+ * produce type errors. If a @ts-expect-error line does NOT
6
+ * produce an error, tsc will report "Unused '@ts-expect-error' directive".
7
+ *
8
+ * Run: npx tsc --noEmit
9
+ */
10
+ import { defineScript } from '../../runtime.js';
11
+ const Props = {
12
+ String: (defaultValue) => ({ __brand: 'StringPropAPI', defaultValue }),
13
+ };
14
+ export default defineScript({
15
+ props: {
16
+ message: Props.String("Hello!"),
17
+ },
18
+ methods: {
19
+ toto({ executor }) {
20
+ executor.asPlayer()?.sendMessage("toto!");
21
+ },
22
+ greet({ executor }) {
23
+ // Methods receive BaseScriptContext — no `methods` field.
24
+ // This avoids circular generic inference.
25
+ executor.asPlayer()?.sendMessage("greet!");
26
+ },
27
+ },
28
+ run({ methods }) {
29
+ methods.toto(); // ✅ valid
30
+ methods.greet(); // ✅ valid
31
+ // @ts-expect-error — 'nope' does not exist on methods
32
+ methods.nope();
33
+ // @ts-expect-error — 'doesNotExist' does not exist on methods
34
+ methods.doesNotExist();
35
+ },
36
+ });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Type-level test for strongly-typed defineScript methods.
3
+ *
4
+ * This file is NOT executed — it only verifies that TypeScript
5
+ * correctly infers method types and provides autocomplete.
6
+ *
7
+ * Run: npx tsc --noEmit
8
+ * If this file compiles, the types are correct.
9
+ */
10
+ export {};
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Type-level test for strongly-typed defineScript methods.
3
+ *
4
+ * This file is NOT executed — it only verifies that TypeScript
5
+ * correctly infers method types and provides autocomplete.
6
+ *
7
+ * Run: npx tsc --noEmit
8
+ * If this file compiles, the types are correct.
9
+ */
10
+ // These should be the stripped signatures:
11
+ const _test1 = {
12
+ greet: (name) => name, // ctx stripped, (name: string) => string
13
+ wave: () => { }, // ctx stripped, () => void
14
+ };
15
+ // Verify the config type accepts methods and that ctx.methods inside run() is strongly typed.
16
+ const _config = {
17
+ props: undefined,
18
+ methods: {
19
+ toto(ctx) {
20
+ ctx.executor.asPlayer()?.sendMessage("toto!");
21
+ },
22
+ greet(ctx) {
23
+ // Methods receive BaseScriptContext — no `methods` field
24
+ ctx.executor.asPlayer()?.sendMessage("greet!");
25
+ },
26
+ },
27
+ run(ctx) {
28
+ ctx.methods.toto();
29
+ ctx.methods.greet();
30
+ // ctx.props should be typed
31
+ const _msg = ctx.props.message;
32
+ const _cnt = ctx.props.count;
33
+ },
34
+ };
35
+ const _emptyCtx = {};
36
+ // Should be Record<string, never> — no methods
37
+ const _emptyWrapped = {};
38
+ console.log("Type tests passed (compile-time only)", _test1, _config, _emptyCtx, _emptyWrapped);
39
+ export {};
@@ -97,6 +97,22 @@ export type EmptyEventSchema = Record<string, never>;
97
97
  * Infer the event payload type from an EventSchema.
98
98
  */
99
99
  export type InferEventPayload<E extends EventSchema, K extends keyof E> = InferPropType<E[K]>;
100
+ /**
101
+ * Strips the first ctx parameter from each method, producing the type
102
+ * available as ctx.methods inside scripts.
103
+ *
104
+ * Given methods like `{ greet(ctx: ScriptContext, ...args): void }`,
105
+ * produces `{ greet(...args): void }` — ctx is auto-injected at runtime.
106
+ */
107
+ export type WrappedMethods<M> = {
108
+ [K in keyof M]: M[K] extends (ctx: never, ...args: infer A) => infer R ? (...args: A) => R : () => unknown;
109
+ };
110
+ /**
111
+ * Script configuration for defineScript() — without methods.
112
+ *
113
+ * @typeParam P - Props schema type
114
+ * @typeParam E - Events schema type
115
+ */
100
116
  export interface ScriptConfig<P extends PropSchema, E extends EventSchema = EmptyEventSchema> {
101
117
  /** Props schema with types and defaults */
102
118
  props?: P;
@@ -124,6 +140,47 @@ export interface ScriptConfig<P extends PropSchema, E extends EventSchema = Empt
124
140
  */
125
141
  run: (this: TypedMcModuleAPI<E>, ctx: ScriptContext<InferProps<P>, E>) => void;
126
142
  }
143
+ /**
144
+ * Script configuration for defineScript() — with strongly-typed methods.
145
+ *
146
+ * Uses a generic `M` to capture the literal shape of the methods object.
147
+ * Each method receives a `ScriptContext` with `WrappedMethods<M>` providing
148
+ * full autocomplete for `ctx.methods.*`.
149
+ *
150
+ * The `methods` field uses a mapped type over `keyof M` so TypeScript
151
+ * can infer `M` from the object literal keys, then constrains each
152
+ * method's signature.
153
+ *
154
+ * @typeParam P - Props schema type
155
+ * @typeParam E - Events schema type
156
+ * @typeParam M - Methods record type (inferred from the methods object literal)
157
+ */
158
+ /** Constraint for the methods record — each method receives BaseScriptContext */
159
+ export type MethodMap<P extends PropSchema, E extends EventSchema> = Record<string, (ctx: BaseScriptContext<InferProps<P>, E>, ...args: unknown[]) => unknown>;
160
+ export type ScriptConfigWithMethods<P extends PropSchema, E extends EventSchema, M extends MethodMap<P, E>> = {
161
+ props?: P;
162
+ events?: E;
163
+ /**
164
+ * Named methods that can be called externally via `process.call("methodName", ...args)`
165
+ * or internally via `ctx.methods.methodName()`.
166
+ *
167
+ * Each method receives `(ctx: BaseScriptContext, ...extraArgs)` — a context without `methods`
168
+ * to avoid circular generic inference. At runtime, Java injects the full context.
169
+ *
170
+ * When called via `ctx.methods` in `run()`, the `ctx` parameter is auto-injected.
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * methods: {
175
+ * greet({ executor }) {
176
+ * executor.asPlayer()?.sendMessage("Hello!");
177
+ * },
178
+ * }
179
+ * ```
180
+ */
181
+ methods: M;
182
+ run: (this: TypedMcModuleAPI<E>, ctx: ScriptContext<InferProps<P>, E, WrappedMethods<M>>) => void;
183
+ };
127
184
  export interface ScriptDefinition<P extends PropSchema, E extends EventSchema = EmptyEventSchema> {
128
185
  props?: P;
129
186
  events?: E;
@@ -260,10 +317,14 @@ export interface ItemDefinition extends ItemConfig {
260
317
  readonly __type: "item";
261
318
  }
262
319
  /**
263
- * Context passed to script run function.
264
- * Contains all APIs and subsystems available to scripts.
320
+ * Base context passed to method functions.
321
+ * Same as ScriptContext but without `methods` to avoid circular generic inference.
322
+ * At runtime, Java actually injects the full context including methods.
323
+ *
324
+ * @typeParam P - Inferred props type
325
+ * @typeParam E - Event schema type
265
326
  */
266
- export interface ScriptContext<P = Record<string, unknown>, E extends EventSchema = EmptyEventSchema> {
327
+ export interface BaseScriptContext<P = Record<string, unknown>, E extends EventSchema = EmptyEventSchema> {
267
328
  /** Process API for script management (typed for events if declared) */
268
329
  process: TypedMcModuleAPI<E>;
269
330
  /** Validated props */
@@ -289,6 +350,33 @@ export interface ScriptContext<P = Record<string, unknown>, E extends EventSchem
289
350
  /** Persistent storage system */
290
351
  storage: StorageAPI;
291
352
  }
353
+ /**
354
+ * Full context passed to the script `run()` function.
355
+ * Extends BaseScriptContext with strongly-typed `methods`.
356
+ *
357
+ * @typeParam P - Inferred props type
358
+ * @typeParam E - Event schema type
359
+ * @typeParam Methods - Strongly-typed methods map (auto-inferred from defineScript)
360
+ */
361
+ export interface ScriptContext<P = Record<string, unknown>, E extends EventSchema = EmptyEventSchema, Methods = Record<string, never>> extends BaseScriptContext<P, E> {
362
+ /**
363
+ * Callable methods defined in defineScript({ methods: { ... } }).
364
+ * These are wrapped so `ctx` is auto-injected — call them directly without passing ctx.
365
+ *
366
+ * Fully typed: autocomplete shows only the methods you defined,
367
+ * and calling a non-existent method is a type error.
368
+ *
369
+ * @example
370
+ * ```typescript
371
+ * run({ methods }) {
372
+ * methods.greet(); // ✅ ctx is auto-injected, autocomplete works
373
+ * methods.farewell("arg"); // ✅ extra args passed through
374
+ * methods.nope(); // ❌ type error — not defined
375
+ * }
376
+ * ```
377
+ */
378
+ methods: Methods;
379
+ }
292
380
  export interface PropSchema {
293
381
  [key: string]: PropAPI;
294
382
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Response from the /packs/upload endpoint.
3
+ */
4
+ export interface UploadResponse {
5
+ success: boolean;
6
+ packId?: string;
7
+ version?: string;
8
+ message?: string;
9
+ error?: string;
10
+ }
11
+ /**
12
+ * Upload a pack zip to the server via HTTP POST.
13
+ *
14
+ * Sends raw zip bytes with application/zip content type.
15
+ * The server saves the zip and hot-loads the pack.
16
+ *
17
+ * @param serverUrl - Server base URL (e.g. "http://localhost:8765")
18
+ * @param token - Authentication token (from `kustom login`)
19
+ * @param buffer - Raw zip bytes
20
+ * @param packId - Pack ID hint for the server
21
+ */
22
+ export declare function uploadPack(serverUrl: string, token: string, buffer: Buffer, packId: string): Promise<UploadResponse>;
package/dist/upload.js ADDED
@@ -0,0 +1,35 @@
1
+ import { normalizeServerUrl } from './credentials.js';
2
+ /**
3
+ * Upload a pack zip to the server via HTTP POST.
4
+ *
5
+ * Sends raw zip bytes with application/zip content type.
6
+ * The server saves the zip and hot-loads the pack.
7
+ *
8
+ * @param serverUrl - Server base URL (e.g. "http://localhost:8765")
9
+ * @param token - Authentication token (from `kustom login`)
10
+ * @param buffer - Raw zip bytes
11
+ * @param packId - Pack ID hint for the server
12
+ */
13
+ export async function uploadPack(serverUrl, token, buffer, packId) {
14
+ const url = `${normalizeServerUrl(serverUrl)}/packs/upload`;
15
+ const response = await fetch(url, {
16
+ method: 'POST',
17
+ headers: {
18
+ 'Authorization': `Bearer ${token}`,
19
+ 'Content-Type': 'application/zip',
20
+ 'X-Pack-Id': packId
21
+ },
22
+ body: buffer
23
+ });
24
+ if (response.status === 401) {
25
+ throw new Error('Authentication failed. Token may be invalid or expired. Run: npx kustom-mc login');
26
+ }
27
+ if (response.status === 403) {
28
+ throw new Error('Permission denied. You may not have upload permissions.');
29
+ }
30
+ const result = await response.json();
31
+ if (!response.ok) {
32
+ throw new Error(result.error || result.message || `Server returned ${response.status}`);
33
+ }
34
+ return result;
35
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kustom-mc",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "CLI and type library for kustompack development",
5
5
  "type": "module",
6
6
  "main": "dist/runtime.js",