@crowdedkingdoms/crowdyjs 8.0.0 → 8.1.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.
Files changed (59) hide show
  1. package/README.md +92 -15
  2. package/dist/client.d.ts +8 -0
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +5 -0
  5. package/dist/crowdy-client.d.ts +22 -0
  6. package/dist/crowdy-client.d.ts.map +1 -1
  7. package/dist/crowdy-client.js +21 -0
  8. package/dist/domains/gameModel.d.ts +54 -3
  9. package/dist/domains/gameModel.d.ts.map +1 -1
  10. package/dist/domains/gameModel.js +67 -4
  11. package/dist/domains/host.d.ts +14 -3
  12. package/dist/domains/host.d.ts.map +1 -1
  13. package/dist/domains/host.js +17 -3
  14. package/dist/domains/organizations.d.ts +3 -3
  15. package/dist/domains/organizations.js +3 -3
  16. package/dist/domains/quotas.d.ts +1 -1
  17. package/dist/domains/quotas.js +1 -1
  18. package/dist/domains/udp.d.ts +28 -17
  19. package/dist/domains/udp.d.ts.map +1 -1
  20. package/dist/domains/udp.js +28 -17
  21. package/dist/generated/graphql.d.ts +366 -6
  22. package/dist/generated/graphql.d.ts.map +1 -1
  23. package/dist/generated/graphql.js +13 -8
  24. package/dist/index.d.ts +3 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +3 -1
  27. package/dist/kit/blueprints.d.ts +259 -0
  28. package/dist/kit/blueprints.d.ts.map +1 -0
  29. package/dist/kit/blueprints.js +480 -0
  30. package/dist/kit/index.d.ts +7 -0
  31. package/dist/kit/index.d.ts.map +1 -0
  32. package/dist/kit/index.js +6 -0
  33. package/dist/kit/inventory.d.ts +111 -0
  34. package/dist/kit/inventory.d.ts.map +1 -0
  35. package/dist/kit/inventory.js +158 -0
  36. package/dist/kit/kit.d.ts +96 -0
  37. package/dist/kit/kit.d.ts.map +1 -0
  38. package/dist/kit/kit.js +98 -0
  39. package/dist/kit/npcs.d.ts +182 -0
  40. package/dist/kit/npcs.d.ts.map +1 -0
  41. package/dist/kit/npcs.js +106 -0
  42. package/dist/kit/objects.d.ts +108 -0
  43. package/dist/kit/objects.d.ts.map +1 -0
  44. package/dist/kit/objects.js +110 -0
  45. package/dist/kit/shared.d.ts +32 -0
  46. package/dist/kit/shared.d.ts.map +1 -0
  47. package/dist/kit/shared.js +39 -0
  48. package/dist/lb-cookie-store.d.ts +20 -0
  49. package/dist/lb-cookie-store.d.ts.map +1 -0
  50. package/dist/lb-cookie-store.js +73 -0
  51. package/dist/realtime.d.ts +20 -5
  52. package/dist/realtime.d.ts.map +1 -1
  53. package/dist/realtime.js +38 -0
  54. package/dist/types.d.ts +22 -6
  55. package/dist/types.d.ts.map +1 -1
  56. package/dist/world.d.ts +13 -8
  57. package/dist/world.d.ts.map +1 -1
  58. package/dist/world.js +13 -8
  59. package/package.json +6 -4
@@ -0,0 +1,480 @@
1
+ /** Serialize a {@link KitInvokePolicy} tree to the wire `invokePolicyJson`. */
2
+ export function kitPolicyJson(policy) {
3
+ return JSON.stringify(policy);
4
+ }
5
+ /** Convert `PascalCase`/`camelCase` to `snake_case` for derived names. */
6
+ export function toSnakeCase(name) {
7
+ return name
8
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
9
+ .replace(/[\s-]+/g, '_')
10
+ .toLowerCase();
11
+ }
12
+ /** Compute the type/function names an inventory blueprint (and its runtime helper) uses. */
13
+ export function inventoryNames(typePrefix = '') {
14
+ const fnPrefix = typePrefix ? `${toSnakeCase(typePrefix)}_` : '';
15
+ return {
16
+ inventoryType: `${typePrefix}Inventory`,
17
+ stackType: `${typePrefix}ItemStack`,
18
+ grantFn: `${fnPrefix}grant_stack`,
19
+ consumeFn: `${fnPrefix}consume_stack`,
20
+ moveFn: `${fnPrefix}move_stack`,
21
+ transferFn: `${fnPrefix}transfer_stack`,
22
+ containsEdge: 'inventory_contains',
23
+ };
24
+ }
25
+ /**
26
+ * Blueprint for a server-authoritative **inventory**: a per-player
27
+ * `Inventory` container plus `ItemStack` containers (`item_id`, `quantity`,
28
+ * `slot`), and owner-gated functions to grant, consume, move, and transfer
29
+ * stacks. Quantity guards live in the invoke policies, so an untrusted client
30
+ * can never overdraw or touch another player's items.
31
+ *
32
+ * Runtime counterpart: `client.kit(appId).inventory`.
33
+ */
34
+ export function inventoryBlueprint(options = {}) {
35
+ const { typePrefix = '', maxSlots = 24, slotCount = 64 } = options;
36
+ const names = inventoryNames(typePrefix);
37
+ const ownerOnly = kitPolicyJson({ type: 'owner_of_self' });
38
+ return {
39
+ name: names.inventoryType,
40
+ containerTypes: [
41
+ {
42
+ typeName: names.inventoryType,
43
+ displayName: names.inventoryType,
44
+ instantiableBy: 'member',
45
+ description: 'A bag of item stacks owned by one player.',
46
+ },
47
+ {
48
+ typeName: names.stackType,
49
+ displayName: names.stackType,
50
+ instantiableBy: 'member',
51
+ description: 'One stack of a single item type in an inventory slot.',
52
+ },
53
+ ],
54
+ propertyDefinitions: [
55
+ {
56
+ containerTypeName: names.inventoryType,
57
+ key: 'max_slots',
58
+ valueType: 'int',
59
+ defaultValueJson: String(maxSlots),
60
+ },
61
+ { containerTypeName: names.stackType, key: 'item_id', valueType: 'string' },
62
+ {
63
+ containerTypeName: names.stackType,
64
+ key: 'quantity',
65
+ valueType: 'int',
66
+ defaultValueJson: '0',
67
+ },
68
+ {
69
+ containerTypeName: names.stackType,
70
+ key: 'slot',
71
+ valueType: 'int',
72
+ defaultValueJson: '0',
73
+ },
74
+ ],
75
+ functions: [
76
+ {
77
+ name: names.grantFn,
78
+ containerTypeName: names.stackType,
79
+ returnType: 'int',
80
+ parameters: [{ name: 'amount', valueType: 'int', required: true }],
81
+ mutations: [
82
+ {
83
+ target: 'self',
84
+ property: 'quantity',
85
+ expression: 'self.quantity + max(0, $amount)',
86
+ },
87
+ ],
88
+ returnExpression: 'self.quantity',
89
+ invokePolicyJson: ownerOnly,
90
+ description: 'Add items to a stack the caller owns.',
91
+ },
92
+ {
93
+ name: names.consumeFn,
94
+ containerTypeName: names.stackType,
95
+ returnType: 'int',
96
+ parameters: [{ name: 'amount', valueType: 'int', required: true }],
97
+ mutations: [
98
+ { target: 'self', property: 'quantity', expression: 'self.quantity - $amount' },
99
+ ],
100
+ returnExpression: 'self.quantity',
101
+ invokePolicyJson: kitPolicyJson({
102
+ type: 'and',
103
+ rules: [
104
+ { type: 'owner_of_self' },
105
+ {
106
+ type: 'condition',
107
+ expression: '$amount > 0 && self.quantity >= $amount',
108
+ },
109
+ ],
110
+ }),
111
+ description: 'Spend items from a stack; refuses to overdraw.',
112
+ },
113
+ {
114
+ name: names.moveFn,
115
+ containerTypeName: names.stackType,
116
+ returnType: 'int',
117
+ parameters: [{ name: 'to_slot', valueType: 'int', required: true }],
118
+ mutations: [
119
+ {
120
+ target: 'self',
121
+ property: 'slot',
122
+ expression: `clamp($to_slot, 0, ${slotCount - 1})`,
123
+ },
124
+ ],
125
+ returnExpression: 'self.slot',
126
+ invokePolicyJson: ownerOnly,
127
+ description: 'Move a stack to another slot.',
128
+ },
129
+ {
130
+ name: names.transferFn,
131
+ containerTypeName: names.stackType,
132
+ returnType: 'int',
133
+ parameters: [
134
+ { name: 'to_id', valueType: 'container_ref', required: true },
135
+ { name: 'amount', valueType: 'int', required: true },
136
+ ],
137
+ mutations: [
138
+ { target: 'self', property: 'quantity', expression: 'self.quantity - $amount' },
139
+ {
140
+ target: 'ref($to_id)',
141
+ property: 'quantity',
142
+ expression: 'ref($to_id).quantity + $amount',
143
+ },
144
+ ],
145
+ returnExpression: 'self.quantity',
146
+ invokePolicyJson: kitPolicyJson({
147
+ type: 'and',
148
+ rules: [
149
+ { type: 'owner_of_self' },
150
+ {
151
+ type: 'condition',
152
+ expression: '$amount > 0 && self.quantity >= $amount && ref($to_id).item_id == self.item_id',
153
+ },
154
+ ],
155
+ }),
156
+ description: 'Atomically move items between two stacks of the same item type.',
157
+ },
158
+ ],
159
+ };
160
+ }
161
+ /** Compute the type/function names a lock blueprint (and its runtime helper) uses. */
162
+ export function lockNames(objectTypeName = 'Lockable', keyTypeName) {
163
+ const snake = toSnakeCase(objectTypeName);
164
+ return {
165
+ objectType: objectTypeName,
166
+ keyType: keyTypeName ?? `${objectTypeName}Key`,
167
+ openFn: `open_${snake}`,
168
+ closeFn: `close_${snake}`,
169
+ };
170
+ }
171
+ function lockAuthorityRule(authority) {
172
+ switch (authority.kind) {
173
+ case 'owner':
174
+ return { type: 'owner_of_self' };
175
+ case 'key':
176
+ // Container ownership is not readable from expressions, so the key
177
+ // mirrors its owner into an `owner_user_id` property; the condition
178
+ // verifies both the match and the ownership server-side.
179
+ return {
180
+ type: 'condition',
181
+ expression: 'ref($key_id).key_id == self.required_key_id && ref($key_id).owner_user_id == $caller_user_id',
182
+ };
183
+ case 'gridPermission':
184
+ return {
185
+ type: 'grid_permission',
186
+ key: authority.key,
187
+ ...(authority.gridId !== undefined ? { gridId: authority.gridId } : {}),
188
+ };
189
+ case 'groupPermission':
190
+ return {
191
+ type: 'group_permission',
192
+ groupId: authority.groupId,
193
+ ...(authority.permission !== undefined
194
+ ? { permission: authority.permission }
195
+ : {}),
196
+ };
197
+ case 'custom':
198
+ return authority.rule;
199
+ }
200
+ }
201
+ /**
202
+ * Blueprint for a **lockable game object** (door, chest, gate, switch) whose
203
+ * `open`/`close` functions are gated by a configurable authority source:
204
+ * ownership, a key item the caller must hold, a runtime grid permission, a
205
+ * team/group permission, or any custom policy rule. Multiple authorities are
206
+ * OR'd, so "the owner, or anyone with the right key" is one blueprint.
207
+ *
208
+ * Runtime counterpart: `client.kit(appId).objects`.
209
+ */
210
+ export function lockBlueprint(options) {
211
+ const authorities = Array.isArray(options.authority)
212
+ ? options.authority
213
+ : [options.authority];
214
+ if (authorities.length === 0) {
215
+ throw new Error('lockBlueprint requires at least one authority source');
216
+ }
217
+ const names = lockNames(options.objectTypeName, options.keyTypeName);
218
+ const usesKey = authorities.some((a) => a.kind === 'key');
219
+ const rules = authorities.map(lockAuthorityRule);
220
+ const policy = rules.length === 1 ? rules[0] : { type: 'or', rules };
221
+ const policyJson = kitPolicyJson(policy);
222
+ const parameters = usesKey
223
+ ? [{ name: 'key_id', valueType: 'container_ref', required: true }]
224
+ : [];
225
+ const containerTypes = [
226
+ {
227
+ typeName: names.objectType,
228
+ displayName: names.objectType,
229
+ instantiableBy: 'admin',
230
+ description: 'A lockable world object operated through gated functions.',
231
+ },
232
+ ];
233
+ const propertyDefinitions = [
234
+ {
235
+ containerTypeName: names.objectType,
236
+ key: 'is_open',
237
+ valueType: 'bool',
238
+ defaultValueJson: 'false',
239
+ },
240
+ ];
241
+ if (usesKey) {
242
+ propertyDefinitions.push({
243
+ containerTypeName: names.objectType,
244
+ key: 'required_key_id',
245
+ valueType: 'string',
246
+ });
247
+ containerTypes.push({
248
+ typeName: names.keyType,
249
+ displayName: names.keyType,
250
+ instantiableBy: 'admin',
251
+ description: 'A key item granting access to matching lockable objects.',
252
+ });
253
+ propertyDefinitions.push({ containerTypeName: names.keyType, key: 'key_id', valueType: 'string' }, {
254
+ containerTypeName: names.keyType,
255
+ key: 'owner_user_id',
256
+ valueType: 'int',
257
+ });
258
+ }
259
+ const openMutation = {
260
+ target: 'self',
261
+ property: 'is_open',
262
+ expression: 'true',
263
+ };
264
+ const closeMutation = {
265
+ target: 'self',
266
+ property: 'is_open',
267
+ expression: 'false',
268
+ };
269
+ return {
270
+ name: names.objectType,
271
+ containerTypes,
272
+ propertyDefinitions,
273
+ functions: [
274
+ {
275
+ name: names.openFn,
276
+ containerTypeName: names.objectType,
277
+ returnType: 'bool',
278
+ parameters,
279
+ mutations: [openMutation],
280
+ returnExpression: 'self.is_open',
281
+ invokePolicyJson: policyJson,
282
+ description: `Open a ${names.objectType}; the invoke policy decides who may.`,
283
+ },
284
+ {
285
+ name: names.closeFn,
286
+ containerTypeName: names.objectType,
287
+ returnType: 'bool',
288
+ parameters,
289
+ mutations: [closeMutation],
290
+ returnExpression: 'self.is_open',
291
+ invokePolicyJson: policyJson,
292
+ description: `Close a ${names.objectType}; same authority as opening.`,
293
+ },
294
+ ],
295
+ };
296
+ }
297
+ /** Compute the function/automation names an NPC behavior deploys under. */
298
+ export function npcBehaviorFunctionName(behavior) {
299
+ return behavior.functionName ?? toSnakeCase(behavior.name);
300
+ }
301
+ /**
302
+ * Blueprint for an **NPC archetype**: an admin-instantiable container type
303
+ * holding the NPC's durable state, one `autonomousInvocable` model function
304
+ * per behavior (gated `is_automation` so players cannot puppet them), and the
305
+ * automations + event triggers that drive those behaviors on the server.
306
+ *
307
+ * Runtime counterpart: `client.kit(appId).npcs`.
308
+ */
309
+ export function npcBlueprint(options) {
310
+ const typeName = options.typeName ?? 'Npc';
311
+ if (options.behaviors.length === 0) {
312
+ throw new Error('npcBlueprint requires at least one behavior');
313
+ }
314
+ const propertyDefinitions = [
315
+ {
316
+ containerTypeName: typeName,
317
+ key: 'role',
318
+ valueType: 'string',
319
+ defaultValueJson: '""',
320
+ },
321
+ { containerTypeName: typeName, key: 'x', valueType: 'float', defaultValueJson: '0' },
322
+ { containerTypeName: typeName, key: 'y', valueType: 'float', defaultValueJson: '0' },
323
+ { containerTypeName: typeName, key: 'z', valueType: 'float', defaultValueJson: '0' },
324
+ {
325
+ containerTypeName: typeName,
326
+ key: 'behavior_state',
327
+ valueType: 'string',
328
+ defaultValueJson: '"idle"',
329
+ },
330
+ {
331
+ containerTypeName: typeName,
332
+ key: 'health',
333
+ valueType: 'int',
334
+ defaultValueJson: '100',
335
+ },
336
+ ...(options.extraProperties ?? []).map((p) => ({
337
+ ...p,
338
+ containerTypeName: typeName,
339
+ })),
340
+ ];
341
+ const functions = [];
342
+ const automations = [];
343
+ const automationTriggers = [];
344
+ for (const behavior of options.behaviors) {
345
+ const functionName = npcBehaviorFunctionName(behavior);
346
+ functions.push({
347
+ name: functionName,
348
+ containerTypeName: typeName,
349
+ parameters: behavior.parameters,
350
+ mutations: behavior.mutations,
351
+ invokePolicyJson: kitPolicyJson({ type: 'is_automation' }),
352
+ autonomousInvocable: true,
353
+ description: `Server-driven NPC behavior for the '${behavior.name}' automation.`,
354
+ });
355
+ const selector = behavior.selector ??
356
+ (behavior.role !== undefined
357
+ ? { selfWhere: [{ key: 'role', op: '==', value: behavior.role }] }
358
+ : undefined);
359
+ const automation = {
360
+ name: behavior.name,
361
+ functionName,
362
+ targetMode: 'type',
363
+ targetTypeName: typeName,
364
+ maxTargets: behavior.maxTargets ?? 8,
365
+ ...(selector ? { selectorJson: JSON.stringify(selector) } : {}),
366
+ ...(behavior.params ? { paramsJson: JSON.stringify(behavior.params) } : {}),
367
+ ...(behavior.runAsUserId !== undefined
368
+ ? { runAsUserId: behavior.runAsUserId }
369
+ : {}),
370
+ };
371
+ if ('intervalMs' in behavior.trigger) {
372
+ automation.triggerType = 'schedule';
373
+ automation.scheduleKind = 'interval';
374
+ automation.intervalMs = behavior.trigger.intervalMs;
375
+ }
376
+ else if ('cronExpr' in behavior.trigger) {
377
+ automation.triggerType = 'schedule';
378
+ automation.scheduleKind = 'cron';
379
+ automation.cronExpr = behavior.trigger.cronExpr;
380
+ }
381
+ else {
382
+ automation.triggerType = 'event';
383
+ automationTriggers.push({
384
+ automationName: behavior.name,
385
+ onEvent: behavior.trigger.onEvent,
386
+ ...(behavior.trigger.functionName !== undefined
387
+ ? { functionName: behavior.trigger.functionName }
388
+ : {}),
389
+ ...(behavior.trigger.containerTypeName !== undefined
390
+ ? { containerTypeName: behavior.trigger.containerTypeName }
391
+ : {}),
392
+ ...(behavior.trigger.propertyKey !== undefined
393
+ ? { propertyKey: behavior.trigger.propertyKey }
394
+ : {}),
395
+ ...(behavior.trigger.debounceMs !== undefined
396
+ ? { debounceMs: behavior.trigger.debounceMs }
397
+ : {}),
398
+ });
399
+ }
400
+ automations.push(automation);
401
+ }
402
+ return {
403
+ name: typeName,
404
+ containerTypes: [
405
+ {
406
+ typeName,
407
+ displayName: typeName,
408
+ instantiableBy: 'admin',
409
+ description: 'A server-driven non-player character.',
410
+ },
411
+ ],
412
+ propertyDefinitions,
413
+ functions,
414
+ automations,
415
+ automationTriggers,
416
+ };
417
+ }
418
+ /**
419
+ * Merge blueprints into a single `gameModelSeed` payload plus the automation
420
+ * upserts, rejecting duplicate type, property, function, or automation names
421
+ * across blueprints (a duplicate almost always means two blueprints need
422
+ * distinct prefixes/type names).
423
+ */
424
+ export function mergeBlueprints(appId, blueprints, options = {}) {
425
+ const containerTypes = [];
426
+ const propertyDefinitions = [];
427
+ const functions = [];
428
+ const containers = [];
429
+ const edges = [];
430
+ const automations = [];
431
+ const automationTriggers = [];
432
+ const seenTypes = new Map();
433
+ const seenProps = new Map();
434
+ const seenFunctions = new Map();
435
+ const seenAutomations = new Map();
436
+ const seenTempIds = new Map();
437
+ const claim = (seen, key, blueprintName, kind) => {
438
+ const existing = seen.get(key);
439
+ if (existing !== undefined) {
440
+ throw new Error(`Blueprint '${blueprintName}' redefines ${kind} '${key}' already defined by blueprint '${existing}'`);
441
+ }
442
+ seen.set(key, blueprintName);
443
+ };
444
+ for (const blueprint of blueprints) {
445
+ for (const type of blueprint.containerTypes ?? []) {
446
+ claim(seenTypes, type.typeName, blueprint.name, 'container type');
447
+ containerTypes.push(type);
448
+ }
449
+ for (const prop of blueprint.propertyDefinitions ?? []) {
450
+ claim(seenProps, `${prop.containerTypeName}.${prop.key}`, blueprint.name, 'property');
451
+ propertyDefinitions.push(prop);
452
+ }
453
+ for (const fn of blueprint.functions ?? []) {
454
+ claim(seenFunctions, fn.name, blueprint.name, 'function');
455
+ functions.push(fn);
456
+ }
457
+ for (const container of blueprint.containers ?? []) {
458
+ claim(seenTempIds, container.tempId, blueprint.name, 'container tempId');
459
+ containers.push(container);
460
+ }
461
+ edges.push(...(blueprint.edges ?? []));
462
+ for (const automation of blueprint.automations ?? []) {
463
+ claim(seenAutomations, automation.name, blueprint.name, 'automation');
464
+ automations.push({ ...automation, appId });
465
+ }
466
+ for (const trigger of blueprint.automationTriggers ?? []) {
467
+ automationTriggers.push({ ...trigger, appId });
468
+ }
469
+ }
470
+ const seedInput = {
471
+ appId,
472
+ ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
473
+ ...(containerTypes.length ? { containerTypes } : {}),
474
+ ...(propertyDefinitions.length ? { propertyDefinitions } : {}),
475
+ ...(functions.length ? { functions } : {}),
476
+ ...(containers.length ? { containers } : {}),
477
+ ...(edges.length ? { edges } : {}),
478
+ };
479
+ return { seedInput, automations, automationTriggers };
480
+ }
@@ -0,0 +1,7 @@
1
+ export { inventoryBlueprint, inventoryNames, kitPolicyJson, lockBlueprint, lockNames, mergeBlueprints, npcBehaviorFunctionName, npcBlueprint, toSnakeCase, type InventoryBlueprintOptions, type InventoryNames, type KitAutomationSpec, type KitAutomationTriggerSpec, type KitBlueprint, type KitInvokePolicy, type LockAuthority, type LockBlueprintOptions, type LockNames, type MergedBlueprints, type NpcBehaviorSpec, type NpcBehaviorTrigger, type NpcBlueprintOptions, } from './blueprints.js';
2
+ export { GameKitClient, type GameKitOptions, type KitDeployResult, } from './kit.js';
3
+ export { InventoryKit, type InventoryKitOptions, type KitItemStack } from './inventory.js';
4
+ export { ObjectsKit, type ObjectsKitOptions } from './objects.js';
5
+ export { NpcsKit, type NpcsKitOptions, type KitNpc } from './npcs.js';
6
+ export { kitInvoke, toKitInvokeResult, type KitInvokeResult, type RawInvokeResult, } from './shared.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/kit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,aAAa,EACb,SAAS,EACT,eAAe,EACf,uBAAuB,EACvB,YAAY,EACZ,WAAW,EACX,KAAK,yBAAyB,EAC9B,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC3F,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { inventoryBlueprint, inventoryNames, kitPolicyJson, lockBlueprint, lockNames, mergeBlueprints, npcBehaviorFunctionName, npcBlueprint, toSnakeCase, } from './blueprints.js';
2
+ export { GameKitClient, } from './kit.js';
3
+ export { InventoryKit } from './inventory.js';
4
+ export { ObjectsKit } from './objects.js';
5
+ export { NpcsKit } from './npcs.js';
6
+ export { kitInvoke, toKitInvokeResult, } from './shared.js';
@@ -0,0 +1,111 @@
1
+ import type { GameModelAPI } from '../domains/gameModel.js';
2
+ import type { Scalars } from '../generated/graphql.js';
3
+ import { type KitInvokeResult } from './shared.js';
4
+ /** Options for {@link InventoryKit}. Must match the deployed blueprint's options. */
5
+ export interface InventoryKitOptions {
6
+ /** The `typePrefix` the inventory blueprint was deployed with. */
7
+ typePrefix?: string;
8
+ }
9
+ /** A parsed view of one item stack. */
10
+ export interface KitItemStack {
11
+ containerId: string;
12
+ displayName: string;
13
+ ownerUserId: string | null;
14
+ itemId: string;
15
+ quantity: number;
16
+ slot: number;
17
+ }
18
+ /**
19
+ * Runtime helpers for the {@link inventoryBlueprint} conventions: find or
20
+ * create the player's inventory, list stacks, and mutate them through the
21
+ * owner-gated model functions. All state lives server-side; every mutation is
22
+ * authority-checked and atomic.
23
+ *
24
+ * Obtained via `client.kit(appId).inventory`.
25
+ */
26
+ export declare class InventoryKit {
27
+ private readonly appId;
28
+ private readonly gameModel;
29
+ private readonly names;
30
+ constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: InventoryKitOptions);
31
+ /**
32
+ * Find the caller's inventory container, creating it when absent. The
33
+ * server assigns ownership to the caller (the type is member-instantiable
34
+ * and `ownerUserId` is omitted on create).
35
+ *
36
+ * @param ownerUserId - The calling player's user id (a decimal string, e.g.
37
+ * from `client.users.me()`), used to recognize an existing inventory.
38
+ */
39
+ ensure(ownerUserId: Scalars['BigInt']['input'], options?: {
40
+ displayName?: string;
41
+ sessionId?: string;
42
+ }): Promise<{
43
+ __typename?: "GmContainer";
44
+ containerId: string;
45
+ appId: string;
46
+ sessionId: string | null;
47
+ typeName: string;
48
+ displayName: string;
49
+ description: string | null;
50
+ ownerUserId: string | null;
51
+ metadataJson: string;
52
+ }>;
53
+ /**
54
+ * List a player's item stacks with parsed properties (`itemId`, `quantity`,
55
+ * `slot`). Fetches each stack's visible state in parallel.
56
+ */
57
+ stacks(ownerUserId: Scalars['BigInt']['input']): Promise<KitItemStack[]>;
58
+ /**
59
+ * Create a new stack owned by the caller (server-assigned ownership).
60
+ * Use {@link grant} afterwards for authority-checked increments; the initial
61
+ * quantity here is a seed value on a container the caller owns anyway.
62
+ */
63
+ createStack(input: {
64
+ itemId: string;
65
+ quantity?: number;
66
+ slot?: number;
67
+ displayName?: string;
68
+ sessionId?: string;
69
+ }): Promise<{
70
+ __typename?: "GmContainer";
71
+ containerId: string;
72
+ appId: string;
73
+ sessionId: string | null;
74
+ typeName: string;
75
+ displayName: string;
76
+ description: string | null;
77
+ ownerUserId: string | null;
78
+ metadataJson: string;
79
+ }>;
80
+ /** Add items to a stack the caller owns. Resolves with the new quantity. */
81
+ grant(stackId: string, amount: number): Promise<KitInvokeResult<number>>;
82
+ /**
83
+ * Spend items from a stack the caller owns. The server refuses to overdraw
84
+ * (`success: false`, nothing written). Resolves with the new quantity.
85
+ */
86
+ consume(stackId: string, amount: number): Promise<KitInvokeResult<number>>;
87
+ /** Move a stack to another slot. Resolves with the new (clamped) slot. */
88
+ move(stackId: string, toSlot: number): Promise<KitInvokeResult<number>>;
89
+ /**
90
+ * Atomically move items between two stacks of the same item type — both
91
+ * writes commit or neither does. The caller must own the source stack.
92
+ * Resolves with the source stack's remaining quantity.
93
+ */
94
+ transfer(fromStackId: string, toStackId: string, amount: number): Promise<KitInvokeResult<number>>;
95
+ /**
96
+ * Record that a stack belongs to an inventory with an
97
+ * `inventory_contains` edge, so {@link contents} can read the whole bag in
98
+ * one traversal.
99
+ */
100
+ linkStack(inventoryId: string, stackId: string): Promise<{
101
+ __typename?: "GmEdge";
102
+ edgeId: string;
103
+ fromContainerId: string;
104
+ toContainerId: string;
105
+ relationshipType: string;
106
+ weight: number | null;
107
+ }>;
108
+ /** Read every stack linked to an inventory (via `inventory_contains` edges). */
109
+ contents(inventoryId: string): Promise<KitItemStack[]>;
110
+ }
111
+ //# sourceMappingURL=inventory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inventory.d.ts","sourceRoot":"","sources":["../../src/kit/inventory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAErB,qFAAqF;AACrF,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,uCAAuC;AACvC,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,qBAAa,YAAY;IAIrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;gBAGpB,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACjC,SAAS,EAAE,YAAY,EACxC,OAAO,GAAE,mBAAwB;IAKnC;;;;;;;OAOG;IACG,MAAM,CACV,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACvC,OAAO,GAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO;;;;;;;;;;;IAmB5D;;;OAGG;IACG,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IA2B9E;;;;OAIG;IACG,WAAW,CAAC,KAAK,EAAE;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;IAcD,4EAA4E;IACtE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAS9E;;;OAGG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAShF,0EAA0E;IACpE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAS7E;;;;OAIG;IACG,QAAQ,CACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IASnC;;;;OAIG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;IASpD,gFAAgF;IAC1E,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CA4B7D"}