@crowdedkingdoms/crowdyjs 8.0.1 → 8.2.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/README.md +62 -1
- package/dist/crowdy-client.d.ts +15 -0
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +17 -0
- package/dist/generated/graphql.d.ts +78 -1
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +7 -7
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/kit/blueprints.d.ts +370 -0
- package/dist/kit/blueprints.d.ts.map +1 -0
- package/dist/kit/blueprints.js +643 -0
- package/dist/kit/index.d.ts +8 -0
- package/dist/kit/index.d.ts.map +1 -0
- package/dist/kit/index.js +7 -0
- package/dist/kit/inventory.d.ts +111 -0
- package/dist/kit/inventory.d.ts.map +1 -0
- package/dist/kit/inventory.js +158 -0
- package/dist/kit/kit.d.ts +101 -0
- package/dist/kit/kit.d.ts.map +1 -0
- package/dist/kit/kit.js +100 -0
- package/dist/kit/npcs.d.ts +182 -0
- package/dist/kit/npcs.d.ts.map +1 -0
- package/dist/kit/npcs.js +106 -0
- package/dist/kit/objects.d.ts +116 -0
- package/dist/kit/objects.d.ts.map +1 -0
- package/dist/kit/objects.js +119 -0
- package/dist/kit/plots.d.ts +81 -0
- package/dist/kit/plots.d.ts.map +1 -0
- package/dist/kit/plots.js +113 -0
- package/dist/kit/shared.d.ts +32 -0
- package/dist/kit/shared.d.ts.map +1 -0
- package/dist/kit/shared.js +39 -0
- package/package.json +1 -1
|
@@ -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"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { inventoryNames } from './blueprints.js';
|
|
2
|
+
import { kitContainerProperties, kitInvoke, } from './shared.js';
|
|
3
|
+
/**
|
|
4
|
+
* Runtime helpers for the {@link inventoryBlueprint} conventions: find or
|
|
5
|
+
* create the player's inventory, list stacks, and mutate them through the
|
|
6
|
+
* owner-gated model functions. All state lives server-side; every mutation is
|
|
7
|
+
* authority-checked and atomic.
|
|
8
|
+
*
|
|
9
|
+
* Obtained via `client.kit(appId).inventory`.
|
|
10
|
+
*/
|
|
11
|
+
export class InventoryKit {
|
|
12
|
+
constructor(appId, gameModel, options = {}) {
|
|
13
|
+
this.appId = appId;
|
|
14
|
+
this.gameModel = gameModel;
|
|
15
|
+
this.names = inventoryNames(options.typePrefix ?? '');
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Find the caller's inventory container, creating it when absent. The
|
|
19
|
+
* server assigns ownership to the caller (the type is member-instantiable
|
|
20
|
+
* and `ownerUserId` is omitted on create).
|
|
21
|
+
*
|
|
22
|
+
* @param ownerUserId - The calling player's user id (a decimal string, e.g.
|
|
23
|
+
* from `client.users.me()`), used to recognize an existing inventory.
|
|
24
|
+
*/
|
|
25
|
+
async ensure(ownerUserId, options = {}) {
|
|
26
|
+
const existing = await this.gameModel.containers({
|
|
27
|
+
appId: this.appId,
|
|
28
|
+
typeName: this.names.inventoryType,
|
|
29
|
+
...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
|
|
30
|
+
});
|
|
31
|
+
const mine = existing.find((c) => c.ownerUserId != null && String(c.ownerUserId) === String(ownerUserId));
|
|
32
|
+
if (mine)
|
|
33
|
+
return mine;
|
|
34
|
+
return this.gameModel.createContainer({
|
|
35
|
+
appId: this.appId,
|
|
36
|
+
typeName: this.names.inventoryType,
|
|
37
|
+
displayName: options.displayName ?? `Inventory ${ownerUserId}`,
|
|
38
|
+
...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* List a player's item stacks with parsed properties (`itemId`, `quantity`,
|
|
43
|
+
* `slot`). Fetches each stack's visible state in parallel.
|
|
44
|
+
*/
|
|
45
|
+
async stacks(ownerUserId) {
|
|
46
|
+
const containers = await this.gameModel.containers({
|
|
47
|
+
appId: this.appId,
|
|
48
|
+
typeName: this.names.stackType,
|
|
49
|
+
});
|
|
50
|
+
const mine = containers.filter((c) => c.ownerUserId != null && String(c.ownerUserId) === String(ownerUserId));
|
|
51
|
+
return Promise.all(mine.map(async (c) => {
|
|
52
|
+
const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
|
|
53
|
+
return {
|
|
54
|
+
containerId: c.containerId,
|
|
55
|
+
displayName: c.displayName,
|
|
56
|
+
ownerUserId: c.ownerUserId != null ? String(c.ownerUserId) : null,
|
|
57
|
+
itemId: String(props.item_id ?? ''),
|
|
58
|
+
quantity: Number(props.quantity ?? 0),
|
|
59
|
+
slot: Number(props.slot ?? 0),
|
|
60
|
+
};
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Create a new stack owned by the caller (server-assigned ownership).
|
|
65
|
+
* Use {@link grant} afterwards for authority-checked increments; the initial
|
|
66
|
+
* quantity here is a seed value on a container the caller owns anyway.
|
|
67
|
+
*/
|
|
68
|
+
async createStack(input) {
|
|
69
|
+
return this.gameModel.createContainer({
|
|
70
|
+
appId: this.appId,
|
|
71
|
+
typeName: this.names.stackType,
|
|
72
|
+
displayName: input.displayName ?? `Stack ${input.itemId}`,
|
|
73
|
+
...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),
|
|
74
|
+
properties: [
|
|
75
|
+
{ key: 'item_id', valueType: 'string', valueJson: JSON.stringify(input.itemId) },
|
|
76
|
+
{ key: 'quantity', valueType: 'int', valueJson: String(input.quantity ?? 0) },
|
|
77
|
+
{ key: 'slot', valueType: 'int', valueJson: String(input.slot ?? 0) },
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/** Add items to a stack the caller owns. Resolves with the new quantity. */
|
|
82
|
+
async grant(stackId, amount) {
|
|
83
|
+
return kitInvoke(this.gameModel, {
|
|
84
|
+
appId: String(this.appId),
|
|
85
|
+
functionName: this.names.grantFn,
|
|
86
|
+
selfContainerId: stackId,
|
|
87
|
+
params: { amount },
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Spend items from a stack the caller owns. The server refuses to overdraw
|
|
92
|
+
* (`success: false`, nothing written). Resolves with the new quantity.
|
|
93
|
+
*/
|
|
94
|
+
async consume(stackId, amount) {
|
|
95
|
+
return kitInvoke(this.gameModel, {
|
|
96
|
+
appId: String(this.appId),
|
|
97
|
+
functionName: this.names.consumeFn,
|
|
98
|
+
selfContainerId: stackId,
|
|
99
|
+
params: { amount },
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/** Move a stack to another slot. Resolves with the new (clamped) slot. */
|
|
103
|
+
async move(stackId, toSlot) {
|
|
104
|
+
return kitInvoke(this.gameModel, {
|
|
105
|
+
appId: String(this.appId),
|
|
106
|
+
functionName: this.names.moveFn,
|
|
107
|
+
selfContainerId: stackId,
|
|
108
|
+
params: { to_slot: toSlot },
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Atomically move items between two stacks of the same item type — both
|
|
113
|
+
* writes commit or neither does. The caller must own the source stack.
|
|
114
|
+
* Resolves with the source stack's remaining quantity.
|
|
115
|
+
*/
|
|
116
|
+
async transfer(fromStackId, toStackId, amount) {
|
|
117
|
+
return kitInvoke(this.gameModel, {
|
|
118
|
+
appId: String(this.appId),
|
|
119
|
+
functionName: this.names.transferFn,
|
|
120
|
+
selfContainerId: fromStackId,
|
|
121
|
+
params: { to_id: toStackId, amount },
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Record that a stack belongs to an inventory with an
|
|
126
|
+
* `inventory_contains` edge, so {@link contents} can read the whole bag in
|
|
127
|
+
* one traversal.
|
|
128
|
+
*/
|
|
129
|
+
async linkStack(inventoryId, stackId) {
|
|
130
|
+
return this.gameModel.addEdge({
|
|
131
|
+
appId: this.appId,
|
|
132
|
+
fromContainerId: inventoryId,
|
|
133
|
+
toContainerId: stackId,
|
|
134
|
+
relationshipType: this.names.containsEdge,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/** Read every stack linked to an inventory (via `inventory_contains` edges). */
|
|
138
|
+
async contents(inventoryId) {
|
|
139
|
+
const result = await this.gameModel.traverse({
|
|
140
|
+
appId: this.appId,
|
|
141
|
+
rootId: inventoryId,
|
|
142
|
+
relationshipType: this.names.containsEdge,
|
|
143
|
+
depth: 1,
|
|
144
|
+
});
|
|
145
|
+
const stacks = result.nodes.filter((n) => n.typeName === this.names.stackType);
|
|
146
|
+
return Promise.all(stacks.map(async (c) => {
|
|
147
|
+
const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
|
|
148
|
+
return {
|
|
149
|
+
containerId: c.containerId,
|
|
150
|
+
displayName: c.displayName,
|
|
151
|
+
ownerUserId: c.ownerUserId != null ? String(c.ownerUserId) : null,
|
|
152
|
+
itemId: String(props.item_id ?? ''),
|
|
153
|
+
quantity: Number(props.quantity ?? 0),
|
|
154
|
+
slot: Number(props.slot ?? 0),
|
|
155
|
+
};
|
|
156
|
+
}));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { GameAppsAPI } from '../domains/gameApps.js';
|
|
2
|
+
import type { GameModelAPI } from '../domains/gameModel.js';
|
|
3
|
+
import type { GameModelSeedMutation, GameModelUpsertAutomationMutation, GameModelUpsertAutomationTriggerMutation, Scalars } from '../generated/graphql.js';
|
|
4
|
+
import { type KitBlueprint } from './blueprints.js';
|
|
5
|
+
import { InventoryKit, type InventoryKitOptions } from './inventory.js';
|
|
6
|
+
import { NpcsKit, type NpcsKitOptions } from './npcs.js';
|
|
7
|
+
import { ObjectsKit, type ObjectsKitOptions } from './objects.js';
|
|
8
|
+
import { PlotsKit, type PlotsKitOptions } from './plots.js';
|
|
9
|
+
/** Options for {@link GameKitClient}, configuring the runtime helpers to match your deployed blueprints. */
|
|
10
|
+
export interface GameKitOptions {
|
|
11
|
+
inventory?: InventoryKitOptions;
|
|
12
|
+
objects?: ObjectsKitOptions;
|
|
13
|
+
npcs?: NpcsKitOptions;
|
|
14
|
+
plots?: PlotsKitOptions;
|
|
15
|
+
}
|
|
16
|
+
/** The result of {@link GameKitClient.deploy}: the seed outcome plus each automation/trigger upserted. */
|
|
17
|
+
export interface KitDeployResult {
|
|
18
|
+
seed: GameModelSeedMutation['gameModelSeed'];
|
|
19
|
+
automations: GameModelUpsertAutomationMutation['gameModelUpsertAutomation'][];
|
|
20
|
+
automationTriggers: GameModelUpsertAutomationTriggerMutation['gameModelUpsertAutomationTrigger'][];
|
|
21
|
+
/** Non-fatal static-analysis warnings from the seed. */
|
|
22
|
+
warnings: string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* App-scoped **Game Kit** facade returned by `client.kit(appId)` — high-level
|
|
26
|
+
* building blocks that map traditional game concepts (inventory, lockable
|
|
27
|
+
* objects with custom permissions, NPCs) onto the Game Model + Automations
|
|
28
|
+
* API. Everything composes `client.gameModel`; no new server surface.
|
|
29
|
+
*
|
|
30
|
+
* Two phases, matching the platform's model:
|
|
31
|
+
*
|
|
32
|
+
* 1. **Studio (admin) loads the rules** — {@link deploy} takes declarative
|
|
33
|
+
* {@link KitBlueprint}s (built with `inventoryBlueprint`, `lockBlueprint`,
|
|
34
|
+
* `npcBlueprint`, or by hand) and seeds the container types, property
|
|
35
|
+
* schemas, policy-gated functions, and automations into the app in one
|
|
36
|
+
* idempotent pass. Requires the app-admin `manage_apps` permission — run
|
|
37
|
+
* it from a trusted admin context, never the shipped game client.
|
|
38
|
+
* 2. **The game client plays** — {@link inventory}, {@link objects}, and
|
|
39
|
+
* {@link npcs} wrap the runtime calls (create/read containers, invoke the
|
|
40
|
+
* gated functions) assuming the blueprint conventions. Authorization is
|
|
41
|
+
* enforced server-side on every call.
|
|
42
|
+
*
|
|
43
|
+
* See the docs guides "Game API → Modeling game concepts" and
|
|
44
|
+
* "CrowdyJS → Game Kit".
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* // Studio setup (admin token):
|
|
49
|
+
* const kit = admin.kit(appId);
|
|
50
|
+
* await kit.deploy([
|
|
51
|
+
* inventoryBlueprint(),
|
|
52
|
+
* lockBlueprint({ objectTypeName: 'Door', authority: { kind: 'key' } }),
|
|
53
|
+
* ]);
|
|
54
|
+
*
|
|
55
|
+
* // Game client (player token):
|
|
56
|
+
* const kit = game.kit(appId);
|
|
57
|
+
* const bag = await kit.inventory.ensure(me.userId);
|
|
58
|
+
* const result = await kit.objects.open(doorId, { keyId });
|
|
59
|
+
* if (!result.success) showLockedMessage(result.errorMessage);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare class GameKitClient {
|
|
63
|
+
private readonly appId;
|
|
64
|
+
private readonly gameModel;
|
|
65
|
+
/** Inventory helpers (per-player bags and item stacks). */
|
|
66
|
+
readonly inventory: InventoryKit;
|
|
67
|
+
/** Lockable-object helpers (doors/chests/gates with custom permissions). */
|
|
68
|
+
readonly objects: ObjectsKit;
|
|
69
|
+
/** NPC helpers (spawn/read instances, manage the automations behind them). */
|
|
70
|
+
readonly npcs: NpcsKit;
|
|
71
|
+
/** Plot helpers (buy/rent land with transactional, enforced grid grants). */
|
|
72
|
+
readonly plots: PlotsKit;
|
|
73
|
+
constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, gameApps: GameAppsAPI, options?: GameKitOptions);
|
|
74
|
+
/**
|
|
75
|
+
* Helpers for an additional lockable object type deployed under a different
|
|
76
|
+
* type name (e.g. both `Door` and `Chest` lock blueprints in one app).
|
|
77
|
+
*/
|
|
78
|
+
objectsFor(objectTypeName: string, keyTypeName?: string): ObjectsKit;
|
|
79
|
+
/**
|
|
80
|
+
* **Studio (admin)** — load blueprints into the app: one transactional
|
|
81
|
+
* `gameModelSeed` for the definitions (and any seed containers/edges),
|
|
82
|
+
* followed by an `upsertAutomation` per automation and an
|
|
83
|
+
* `upsertAutomationTrigger` per event trigger. Idempotent: definitions
|
|
84
|
+
* upsert on their names, automations key on the automation name.
|
|
85
|
+
*
|
|
86
|
+
* Requires the app-admin `manage_apps` permission.
|
|
87
|
+
*
|
|
88
|
+
* @param blueprints - The blueprints to deploy. Duplicate type/function/
|
|
89
|
+
* automation names across blueprints throw before anything is sent.
|
|
90
|
+
* @param options - `sessionId` scopes any seed containers to a session.
|
|
91
|
+
* @returns A {@link KitDeployResult} with the seed counts, the upserted
|
|
92
|
+
* automations/triggers, and any non-fatal seed `warnings`.
|
|
93
|
+
* @throws {CrowdyGraphQLError} `FORBIDDEN` (`requiredPermission ===
|
|
94
|
+
* 'manage_apps'`) without app-admin, or `BAD_USER_INPUT` for definitions
|
|
95
|
+
* that fail to compile.
|
|
96
|
+
*/
|
|
97
|
+
deploy(blueprints: KitBlueprint | KitBlueprint[], options?: {
|
|
98
|
+
sessionId?: string;
|
|
99
|
+
}): Promise<KitDeployResult>;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=kit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../../src/kit/kit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EACV,qBAAqB,EACrB,iCAAiC,EACjC,wCAAwC,EACxC,OAAO,EACR,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAE5D,4GAA4G;AAC5G,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,KAAK,CAAC,EAAE,eAAe,CAAC;CACzB;AAED,0GAA0G;AAC1G,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAC;IAC7C,WAAW,EAAE,iCAAiC,CAAC,2BAA2B,CAAC,EAAE,CAAC;IAC9E,kBAAkB,EAAE,wCAAwC,CAAC,kCAAkC,CAAC,EAAE,CAAC;IACnG,wDAAwD;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,qBAAa,aAAa;IAWtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAX5B,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;gBAGN,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACjC,SAAS,EAAE,YAAY,EACxC,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE,cAAmB;IAQ9B;;;OAGG;IACH,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU;IAOpE;;;;;;;;;;;;;;;;;OAiBG;IACG,MAAM,CACV,UAAU,EAAE,YAAY,GAAG,YAAY,EAAE,EACzC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GACnC,OAAO,CAAC,eAAe,CAAC;CAsB5B"}
|
package/dist/kit/kit.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { mergeBlueprints } from './blueprints.js';
|
|
2
|
+
import { InventoryKit } from './inventory.js';
|
|
3
|
+
import { NpcsKit } from './npcs.js';
|
|
4
|
+
import { ObjectsKit } from './objects.js';
|
|
5
|
+
import { PlotsKit } from './plots.js';
|
|
6
|
+
/**
|
|
7
|
+
* App-scoped **Game Kit** facade returned by `client.kit(appId)` — high-level
|
|
8
|
+
* building blocks that map traditional game concepts (inventory, lockable
|
|
9
|
+
* objects with custom permissions, NPCs) onto the Game Model + Automations
|
|
10
|
+
* API. Everything composes `client.gameModel`; no new server surface.
|
|
11
|
+
*
|
|
12
|
+
* Two phases, matching the platform's model:
|
|
13
|
+
*
|
|
14
|
+
* 1. **Studio (admin) loads the rules** — {@link deploy} takes declarative
|
|
15
|
+
* {@link KitBlueprint}s (built with `inventoryBlueprint`, `lockBlueprint`,
|
|
16
|
+
* `npcBlueprint`, or by hand) and seeds the container types, property
|
|
17
|
+
* schemas, policy-gated functions, and automations into the app in one
|
|
18
|
+
* idempotent pass. Requires the app-admin `manage_apps` permission — run
|
|
19
|
+
* it from a trusted admin context, never the shipped game client.
|
|
20
|
+
* 2. **The game client plays** — {@link inventory}, {@link objects}, and
|
|
21
|
+
* {@link npcs} wrap the runtime calls (create/read containers, invoke the
|
|
22
|
+
* gated functions) assuming the blueprint conventions. Authorization is
|
|
23
|
+
* enforced server-side on every call.
|
|
24
|
+
*
|
|
25
|
+
* See the docs guides "Game API → Modeling game concepts" and
|
|
26
|
+
* "CrowdyJS → Game Kit".
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* // Studio setup (admin token):
|
|
31
|
+
* const kit = admin.kit(appId);
|
|
32
|
+
* await kit.deploy([
|
|
33
|
+
* inventoryBlueprint(),
|
|
34
|
+
* lockBlueprint({ objectTypeName: 'Door', authority: { kind: 'key' } }),
|
|
35
|
+
* ]);
|
|
36
|
+
*
|
|
37
|
+
* // Game client (player token):
|
|
38
|
+
* const kit = game.kit(appId);
|
|
39
|
+
* const bag = await kit.inventory.ensure(me.userId);
|
|
40
|
+
* const result = await kit.objects.open(doorId, { keyId });
|
|
41
|
+
* if (!result.success) showLockedMessage(result.errorMessage);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export class GameKitClient {
|
|
45
|
+
constructor(appId, gameModel, gameApps, options = {}) {
|
|
46
|
+
this.appId = appId;
|
|
47
|
+
this.gameModel = gameModel;
|
|
48
|
+
this.inventory = new InventoryKit(appId, gameModel, options.inventory);
|
|
49
|
+
this.objects = new ObjectsKit(appId, gameModel, options.objects);
|
|
50
|
+
this.npcs = new NpcsKit(appId, gameModel, options.npcs);
|
|
51
|
+
this.plots = new PlotsKit(appId, gameModel, gameApps, options.plots);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Helpers for an additional lockable object type deployed under a different
|
|
55
|
+
* type name (e.g. both `Door` and `Chest` lock blueprints in one app).
|
|
56
|
+
*/
|
|
57
|
+
objectsFor(objectTypeName, keyTypeName) {
|
|
58
|
+
return new ObjectsKit(this.appId, this.gameModel, {
|
|
59
|
+
objectTypeName,
|
|
60
|
+
keyTypeName,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* **Studio (admin)** — load blueprints into the app: one transactional
|
|
65
|
+
* `gameModelSeed` for the definitions (and any seed containers/edges),
|
|
66
|
+
* followed by an `upsertAutomation` per automation and an
|
|
67
|
+
* `upsertAutomationTrigger` per event trigger. Idempotent: definitions
|
|
68
|
+
* upsert on their names, automations key on the automation name.
|
|
69
|
+
*
|
|
70
|
+
* Requires the app-admin `manage_apps` permission.
|
|
71
|
+
*
|
|
72
|
+
* @param blueprints - The blueprints to deploy. Duplicate type/function/
|
|
73
|
+
* automation names across blueprints throw before anything is sent.
|
|
74
|
+
* @param options - `sessionId` scopes any seed containers to a session.
|
|
75
|
+
* @returns A {@link KitDeployResult} with the seed counts, the upserted
|
|
76
|
+
* automations/triggers, and any non-fatal seed `warnings`.
|
|
77
|
+
* @throws {CrowdyGraphQLError} `FORBIDDEN` (`requiredPermission ===
|
|
78
|
+
* 'manage_apps'`) without app-admin, or `BAD_USER_INPUT` for definitions
|
|
79
|
+
* that fail to compile.
|
|
80
|
+
*/
|
|
81
|
+
async deploy(blueprints, options = {}) {
|
|
82
|
+
const list = Array.isArray(blueprints) ? blueprints : [blueprints];
|
|
83
|
+
const merged = mergeBlueprints(this.appId, list, options);
|
|
84
|
+
const seed = await this.gameModel.seed(merged.seedInput);
|
|
85
|
+
const automations = [];
|
|
86
|
+
for (const automation of merged.automations) {
|
|
87
|
+
automations.push(await this.gameModel.upsertAutomation(automation));
|
|
88
|
+
}
|
|
89
|
+
const automationTriggers = [];
|
|
90
|
+
for (const trigger of merged.automationTriggers) {
|
|
91
|
+
automationTriggers.push(await this.gameModel.upsertAutomationTrigger(trigger));
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
seed,
|
|
95
|
+
automations,
|
|
96
|
+
automationTriggers,
|
|
97
|
+
warnings: [...(seed.warnings ?? [])],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import type { GameModelAPI } from '../domains/gameModel.js';
|
|
2
|
+
import type { Scalars, SeedPropertyInput } from '../generated/graphql.js';
|
|
3
|
+
/** Options for {@link NpcsKit}. Must match the deployed NPC blueprint. */
|
|
4
|
+
export interface NpcsKitOptions {
|
|
5
|
+
/** The `typeName` the NPC blueprint was deployed with. Defaults to `'Npc'`. */
|
|
6
|
+
typeName?: string;
|
|
7
|
+
}
|
|
8
|
+
/** A parsed view of one live NPC. */
|
|
9
|
+
export interface KitNpc {
|
|
10
|
+
containerId: string;
|
|
11
|
+
displayName: string;
|
|
12
|
+
role: string;
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
z: number;
|
|
16
|
+
behaviorState: string;
|
|
17
|
+
health: number;
|
|
18
|
+
/** All visible properties, including any extras your blueprint added. */
|
|
19
|
+
properties: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Runtime helpers for the {@link npcBlueprint} conventions: spawn NPC
|
|
23
|
+
* instances, read their server-driven state, and manage/monitor the
|
|
24
|
+
* automations behind them. Behaviors run in the API server — clients only
|
|
25
|
+
* re-read state (or listen for model-driven notifications) and render.
|
|
26
|
+
*
|
|
27
|
+
* Spawning and the automation management/monitoring calls are studio/admin
|
|
28
|
+
* operations (`manage_apps`); reads are player-safe.
|
|
29
|
+
*
|
|
30
|
+
* Obtained via `client.kit(appId).npcs`.
|
|
31
|
+
*/
|
|
32
|
+
export declare class NpcsKit {
|
|
33
|
+
private readonly appId;
|
|
34
|
+
private readonly gameModel;
|
|
35
|
+
private readonly typeName;
|
|
36
|
+
constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: NpcsKitOptions);
|
|
37
|
+
/** Spawn a live NPC instance (admin — the type is admin-instantiable). */
|
|
38
|
+
spawn(input: {
|
|
39
|
+
displayName: string;
|
|
40
|
+
role?: string;
|
|
41
|
+
position?: {
|
|
42
|
+
x: number;
|
|
43
|
+
y: number;
|
|
44
|
+
z: number;
|
|
45
|
+
};
|
|
46
|
+
properties?: SeedPropertyInput[];
|
|
47
|
+
sessionId?: string;
|
|
48
|
+
}): Promise<{
|
|
49
|
+
__typename?: "GmContainer";
|
|
50
|
+
containerId: string;
|
|
51
|
+
appId: string;
|
|
52
|
+
sessionId: string | null;
|
|
53
|
+
typeName: string;
|
|
54
|
+
displayName: string;
|
|
55
|
+
description: string | null;
|
|
56
|
+
ownerUserId: string | null;
|
|
57
|
+
metadataJson: string;
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* List live NPCs with parsed state, optionally filtered by `role`. Fetches
|
|
61
|
+
* each NPC's visible properties in parallel — fine for the bounded NPC
|
|
62
|
+
* populations automations are designed around.
|
|
63
|
+
*/
|
|
64
|
+
list(options?: {
|
|
65
|
+
role?: string;
|
|
66
|
+
sessionId?: string;
|
|
67
|
+
}): Promise<KitNpc[]>;
|
|
68
|
+
/** Read one NPC's current server-side state. */
|
|
69
|
+
state(npcId: string): Promise<KitNpc>;
|
|
70
|
+
/** Run one of the NPC automations immediately (admin; useful for testing). */
|
|
71
|
+
runNow(automationName: string): Promise<{
|
|
72
|
+
__typename?: "GmAutomationRun";
|
|
73
|
+
runId: string;
|
|
74
|
+
appId: string;
|
|
75
|
+
automationId: string;
|
|
76
|
+
automationName: string;
|
|
77
|
+
triggerSource: string;
|
|
78
|
+
parentRunId: string | null;
|
|
79
|
+
cascadeDepth: number;
|
|
80
|
+
startedAt: string;
|
|
81
|
+
finishedAt: string | null;
|
|
82
|
+
durationUs: number;
|
|
83
|
+
targets: number;
|
|
84
|
+
invocations: number;
|
|
85
|
+
mutations: number;
|
|
86
|
+
fnCalls: number;
|
|
87
|
+
gasUsed: number;
|
|
88
|
+
success: boolean;
|
|
89
|
+
errorMessage: string | null;
|
|
90
|
+
circuitAction: string | null;
|
|
91
|
+
computeUnits: number;
|
|
92
|
+
}>;
|
|
93
|
+
/**
|
|
94
|
+
* Pause or resume an NPC automation (admin). Re-enabling also resets a
|
|
95
|
+
* tripped failure circuit.
|
|
96
|
+
*/
|
|
97
|
+
setEnabled(automationName: string, enabled: boolean): Promise<{
|
|
98
|
+
__typename?: "GmAutomation";
|
|
99
|
+
automationId: string;
|
|
100
|
+
appId: string;
|
|
101
|
+
name: string;
|
|
102
|
+
description: string | null;
|
|
103
|
+
enabled: boolean;
|
|
104
|
+
functionName: string;
|
|
105
|
+
targetMode: string;
|
|
106
|
+
selfContainerId: string | null;
|
|
107
|
+
targetTypeName: string | null;
|
|
108
|
+
sessionId: string | null;
|
|
109
|
+
paramsJson: string;
|
|
110
|
+
selectorJson: string | null;
|
|
111
|
+
runAsUserId: string | null;
|
|
112
|
+
triggerType: string;
|
|
113
|
+
scheduleKind: string | null;
|
|
114
|
+
intervalMs: number | null;
|
|
115
|
+
cronExpr: string | null;
|
|
116
|
+
maxTargets: number;
|
|
117
|
+
maxFnDepth: number | null;
|
|
118
|
+
gasLimit: number | null;
|
|
119
|
+
runTimeoutMs: number | null;
|
|
120
|
+
maxRunsPerMinute: number;
|
|
121
|
+
failureThreshold: number;
|
|
122
|
+
cooldownMs: number;
|
|
123
|
+
circuitState: string;
|
|
124
|
+
consecutiveFailures: number;
|
|
125
|
+
pausedUntil: string | null;
|
|
126
|
+
lastError: string | null;
|
|
127
|
+
lastRunAt: string | null;
|
|
128
|
+
nextRunAt: string | null;
|
|
129
|
+
}>;
|
|
130
|
+
/** Aggregate "what are my NPCs doing" stats over a recent window (admin). */
|
|
131
|
+
stats(windowMinutes?: number): Promise<{
|
|
132
|
+
__typename?: "GmAutomationStats";
|
|
133
|
+
windowMinutes: number;
|
|
134
|
+
totalRuns: number;
|
|
135
|
+
failedRuns: number;
|
|
136
|
+
failureRatePct: number;
|
|
137
|
+
runsPerMinute: number;
|
|
138
|
+
totalInvocations: number;
|
|
139
|
+
totalMutations: number;
|
|
140
|
+
totalComputeUnits: number;
|
|
141
|
+
avgDurationUs: number;
|
|
142
|
+
byAutomation: Array<{
|
|
143
|
+
__typename?: "GmAutomationStat";
|
|
144
|
+
automationName: string;
|
|
145
|
+
runs: number;
|
|
146
|
+
failures: number;
|
|
147
|
+
invocations: number;
|
|
148
|
+
computeUnits: number;
|
|
149
|
+
avgDurationUs: number;
|
|
150
|
+
circuitState: string;
|
|
151
|
+
}>;
|
|
152
|
+
}>;
|
|
153
|
+
/** Recent automation run history, newest first (admin). */
|
|
154
|
+
runs(options?: {
|
|
155
|
+
automationName?: string;
|
|
156
|
+
success?: boolean;
|
|
157
|
+
limit?: number;
|
|
158
|
+
}): Promise<{
|
|
159
|
+
__typename?: "GmAutomationRun";
|
|
160
|
+
runId: string;
|
|
161
|
+
appId: string;
|
|
162
|
+
automationId: string;
|
|
163
|
+
automationName: string;
|
|
164
|
+
triggerSource: string;
|
|
165
|
+
parentRunId: string | null;
|
|
166
|
+
cascadeDepth: number;
|
|
167
|
+
startedAt: string;
|
|
168
|
+
finishedAt: string | null;
|
|
169
|
+
durationUs: number;
|
|
170
|
+
targets: number;
|
|
171
|
+
invocations: number;
|
|
172
|
+
mutations: number;
|
|
173
|
+
fnCalls: number;
|
|
174
|
+
gasUsed: number;
|
|
175
|
+
success: boolean;
|
|
176
|
+
errorMessage: string | null;
|
|
177
|
+
circuitAction: string | null;
|
|
178
|
+
computeUnits: number;
|
|
179
|
+
}[]>;
|
|
180
|
+
private toNpc;
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=npcs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npcs.d.ts","sourceRoot":"","sources":["../../src/kit/npcs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG1E,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qCAAqC;AACrC,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED;;;;;;;;;;GAUG;AACH,qBAAa,OAAO;IAIhB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAGf,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACjC,SAAS,EAAE,YAAY,EACxC,OAAO,GAAE,cAAmB;IAK9B,0EAA0E;IACpE,KAAK,CAAC,KAAK,EAAE;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC/C,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;QACjC,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;IAuBD;;;;OAIG;IACG,IAAI,CAAC,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAclF,gDAAgD;IAC1C,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ3C,8EAA8E;IACxE,MAAM,CAAC,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;IAInC;;;OAGG;IACG,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQzD,6EAA6E;IACvE,KAAK,CAAC,aAAa,CAAC,EAAE,MAAM;;;;;;;;;;;;sBA+B+2gc,CAAC;;;;;;;;;;IAxBl5gc,2DAA2D;IACrD,IAAI,CAAC,OAAO,GAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO;;;;;;;;;;;;;;;;;;;;;;YAIzE,KAAK;CAkBpB"}
|