@crowdedkingdoms/crowdyjs 8.7.0 → 8.9.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/MIGRATION.md +85 -0
- package/README.md +2 -2
- package/dist/domains/compute.d.ts +12 -1
- package/dist/domains/compute.d.ts.map +1 -1
- package/dist/domains/compute.js +18 -1
- package/dist/generated/graphql.d.ts +60 -0
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/kit/abilities.d.ts +66 -0
- package/dist/kit/abilities.d.ts.map +1 -0
- package/dist/kit/abilities.js +71 -0
- package/dist/kit/blueprints/index.d.ts +2 -0
- package/dist/kit/blueprints/index.d.ts.map +1 -1
- package/dist/kit/blueprints/index.js +2 -0
- package/dist/kit/blueprints/liveops.d.ts +42 -0
- package/dist/kit/blueprints/liveops.d.ts.map +1 -0
- package/dist/kit/blueprints/liveops.js +170 -0
- package/dist/kit/blueprints/moderation.d.ts +32 -0
- package/dist/kit/blueprints/moderation.d.ts.map +1 -0
- package/dist/kit/blueprints/moderation.js +140 -0
- package/dist/kit/decks.d.ts +33 -1
- package/dist/kit/decks.d.ts.map +1 -1
- package/dist/kit/decks.js +49 -1
- package/dist/kit/director.d.ts +88 -0
- package/dist/kit/director.d.ts.map +1 -0
- package/dist/kit/director.js +86 -0
- package/dist/kit/economy.d.ts +46 -1
- package/dist/kit/economy.d.ts.map +1 -1
- package/dist/kit/economy.js +63 -1
- package/dist/kit/index.d.ts +14 -3
- package/dist/kit/index.d.ts.map +1 -1
- package/dist/kit/index.js +14 -3
- package/dist/kit/instances.d.ts +52 -0
- package/dist/kit/instances.d.ts.map +1 -0
- package/dist/kit/instances.js +60 -0
- package/dist/kit/kit.d.ts +60 -0
- package/dist/kit/kit.d.ts.map +1 -1
- package/dist/kit/kit.js +47 -5
- package/dist/kit/leaderboards.d.ts +21 -1
- package/dist/kit/leaderboards.d.ts.map +1 -1
- package/dist/kit/leaderboards.js +40 -1
- package/dist/kit/liveops.d.ts +112 -0
- package/dist/kit/liveops.d.ts.map +1 -0
- package/dist/kit/liveops.js +183 -0
- package/dist/kit/loot.d.ts +22 -1
- package/dist/kit/loot.d.ts.map +1 -1
- package/dist/kit/loot.js +41 -1
- package/dist/kit/matches.d.ts +33 -1
- package/dist/kit/matches.d.ts.map +1 -1
- package/dist/kit/matches.js +56 -1
- package/dist/kit/matchmaking.d.ts +57 -0
- package/dist/kit/matchmaking.d.ts.map +1 -0
- package/dist/kit/matchmaking.js +59 -0
- package/dist/kit/minigames.d.ts +30 -0
- package/dist/kit/minigames.d.ts.map +1 -0
- package/dist/kit/minigames.js +38 -0
- package/dist/kit/moderation.d.ts +73 -0
- package/dist/kit/moderation.d.ts.map +1 -0
- package/dist/kit/moderation.js +103 -0
- package/dist/kit/movement.d.ts +78 -0
- package/dist/kit/movement.d.ts.map +1 -0
- package/dist/kit/movement.js +103 -0
- package/dist/kit/npcs.d.ts.map +1 -1
- package/dist/kit/quests.d.ts +57 -0
- package/dist/kit/quests.d.ts.map +1 -1
- package/dist/kit/quests.js +72 -0
- package/dist/kit/racing.d.ts +85 -0
- package/dist/kit/racing.d.ts.map +1 -0
- package/dist/kit/racing.js +99 -0
- package/dist/kit/social.d.ts.map +1 -1
- package/dist/kit/telemetry.d.ts +66 -0
- package/dist/kit/telemetry.d.ts.map +1 -0
- package/dist/kit/telemetry.js +133 -0
- package/dist/kit/territory.d.ts +97 -0
- package/dist/kit/territory.d.ts.map +1 -0
- package/dist/kit/territory.js +114 -0
- package/dist/kit/wire.d.ts +88 -0
- package/dist/kit/wire.d.ts.map +1 -1
- package/dist/kit/wire.js +110 -0
- package/package.json +1 -1
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { GameModelAPI } from '../domains/gameModel.js';
|
|
2
|
+
import type { Scalars } from '../generated/graphql.js';
|
|
3
|
+
import type { EngineDetector } from './engine.js';
|
|
4
|
+
/** Options for {@link LiveopsKit}. */
|
|
5
|
+
export interface LiveopsKitOptions {
|
|
6
|
+
/** The `typePrefix` the liveops blueprint was deployed with. */
|
|
7
|
+
typePrefix?: string;
|
|
8
|
+
/** The scheduler engine module name. Defaults to `'liveops-scheduler'`. */
|
|
9
|
+
moduleName?: string;
|
|
10
|
+
}
|
|
11
|
+
/** A parsed event window. */
|
|
12
|
+
export interface KitEventWindow {
|
|
13
|
+
containerId: string;
|
|
14
|
+
windowId: string;
|
|
15
|
+
active: boolean;
|
|
16
|
+
opensAtMs: number;
|
|
17
|
+
closesAtMs: number;
|
|
18
|
+
modifiers: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
/** A parsed season definition (+ its battle-pass composition). */
|
|
21
|
+
export interface KitSeason {
|
|
22
|
+
containerId: string;
|
|
23
|
+
seasonId: string;
|
|
24
|
+
active: boolean;
|
|
25
|
+
startsAtMs: number;
|
|
26
|
+
endsAtMs: number;
|
|
27
|
+
passTrack: string;
|
|
28
|
+
passFeatures: string[];
|
|
29
|
+
}
|
|
30
|
+
/** A parsed type-98 zone-change event (BR circles, event areas). */
|
|
31
|
+
export interface ZoneChangeEvent {
|
|
32
|
+
kind: string;
|
|
33
|
+
phase: number | null;
|
|
34
|
+
radiusNow: number;
|
|
35
|
+
centerX: number;
|
|
36
|
+
centerZ: number;
|
|
37
|
+
body: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Runtime helpers for the liveops blueprint: event windows (admin CRUD +
|
|
41
|
+
* active reads — engine-backed when the liveops-scheduler is deployed),
|
|
42
|
+
* seasons with battle-pass composition, and the type-98 zone-change parser.
|
|
43
|
+
*
|
|
44
|
+
* Obtained via `client.kit(appId).liveops`.
|
|
45
|
+
*/
|
|
46
|
+
export declare class LiveopsKit {
|
|
47
|
+
private readonly appId;
|
|
48
|
+
private readonly gameModel;
|
|
49
|
+
private readonly engines?;
|
|
50
|
+
private readonly names;
|
|
51
|
+
private readonly moduleName;
|
|
52
|
+
constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: LiveopsKitOptions, engines?: EngineDetector | undefined);
|
|
53
|
+
/** Is the liveops-scheduler engine deployed + enabled (cached)? */
|
|
54
|
+
engineAvailable(): Promise<boolean>;
|
|
55
|
+
/** STUDIO (admin) — create an event window. */
|
|
56
|
+
defineWindow(input: {
|
|
57
|
+
windowId: string;
|
|
58
|
+
displayName?: string;
|
|
59
|
+
opensAtMs?: number;
|
|
60
|
+
closesAtMs?: number;
|
|
61
|
+
modifiers?: Record<string, unknown>;
|
|
62
|
+
}): Promise<{
|
|
63
|
+
__typename?: "GmContainer";
|
|
64
|
+
containerId: string;
|
|
65
|
+
appId: string;
|
|
66
|
+
sessionId: string | null;
|
|
67
|
+
typeName: string;
|
|
68
|
+
displayName: string;
|
|
69
|
+
description: string | null;
|
|
70
|
+
ownerUserId: string | null;
|
|
71
|
+
metadataJson: string;
|
|
72
|
+
}>;
|
|
73
|
+
/** Every window (model read). */
|
|
74
|
+
windows(): Promise<KitEventWindow[]>;
|
|
75
|
+
/**
|
|
76
|
+
* The ACTIVE windows. Engine path (scheduler deployed): the module's
|
|
77
|
+
* authoritative view; otherwise filters the model read.
|
|
78
|
+
*/
|
|
79
|
+
activeWindows(): Promise<KitEventWindow[]>;
|
|
80
|
+
/** STUDIO (admin/automation) — open a window through the model function. */
|
|
81
|
+
openWindow(windowContainerId: string, sessionId?: string): Promise<import("./shared.js").KitInvokeResult<boolean>>;
|
|
82
|
+
/** STUDIO (admin/automation) — close a window through the model function. */
|
|
83
|
+
closeWindow(windowContainerId: string, sessionId?: string): Promise<import("./shared.js").KitInvokeResult<boolean>>;
|
|
84
|
+
/** STUDIO (admin) — create a season (+ battle-pass composition). */
|
|
85
|
+
defineSeason(input: {
|
|
86
|
+
seasonId: string;
|
|
87
|
+
displayName?: string;
|
|
88
|
+
startsAtMs?: number;
|
|
89
|
+
endsAtMs?: number;
|
|
90
|
+
passTrack?: string;
|
|
91
|
+
passFeatures?: string[];
|
|
92
|
+
}): Promise<{
|
|
93
|
+
__typename?: "GmContainer";
|
|
94
|
+
containerId: string;
|
|
95
|
+
appId: string;
|
|
96
|
+
sessionId: string | null;
|
|
97
|
+
typeName: string;
|
|
98
|
+
displayName: string;
|
|
99
|
+
description: string | null;
|
|
100
|
+
ownerUserId: string | null;
|
|
101
|
+
metadataJson: string;
|
|
102
|
+
}>;
|
|
103
|
+
/** Every season (model read). */
|
|
104
|
+
seasons(): Promise<KitSeason[]>;
|
|
105
|
+
/** The active season, when one exists. */
|
|
106
|
+
currentSeason(): Promise<KitSeason | null>;
|
|
107
|
+
/** STUDIO (admin/automation) — activate a season through the model function. */
|
|
108
|
+
activateSeason(seasonContainerId: string, sessionId?: string): Promise<import("./shared.js").KitInvokeResult<boolean>>;
|
|
109
|
+
/** Parse a type-98 zone-change server event (BR circles, event areas). */
|
|
110
|
+
parseZoneChange(bytes: Uint8Array): ZoneChangeEvent | null;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=liveops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liveops.d.ts","sourceRoot":"","sources":["../../src/kit/liveops.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { liveopsNames } from './blueprints/liveops.js';
|
|
2
|
+
import { kitContainerProperties, kitInvoke } from './shared.js';
|
|
3
|
+
import { parseEngineEvent, EVENT_ZONE_CHANGE } from './wire.js';
|
|
4
|
+
/**
|
|
5
|
+
* Runtime helpers for the liveops blueprint: event windows (admin CRUD +
|
|
6
|
+
* active reads — engine-backed when the liveops-scheduler is deployed),
|
|
7
|
+
* seasons with battle-pass composition, and the type-98 zone-change parser.
|
|
8
|
+
*
|
|
9
|
+
* Obtained via `client.kit(appId).liveops`.
|
|
10
|
+
*/
|
|
11
|
+
export class LiveopsKit {
|
|
12
|
+
constructor(appId, gameModel, options = {}, engines) {
|
|
13
|
+
this.appId = appId;
|
|
14
|
+
this.gameModel = gameModel;
|
|
15
|
+
this.engines = engines;
|
|
16
|
+
this.names = liveopsNames(options.typePrefix ?? '');
|
|
17
|
+
this.moduleName = options.moduleName ?? 'liveops-scheduler';
|
|
18
|
+
}
|
|
19
|
+
/** Is the liveops-scheduler engine deployed + enabled (cached)? */
|
|
20
|
+
engineAvailable() {
|
|
21
|
+
if (!this.engines)
|
|
22
|
+
return Promise.resolve(false);
|
|
23
|
+
return this.engines.has(this.moduleName);
|
|
24
|
+
}
|
|
25
|
+
/** STUDIO (admin) — create an event window. */
|
|
26
|
+
async defineWindow(input) {
|
|
27
|
+
return this.gameModel.createContainer({
|
|
28
|
+
appId: this.appId,
|
|
29
|
+
typeName: this.names.windowType,
|
|
30
|
+
displayName: input.displayName ?? `Window ${input.windowId}`,
|
|
31
|
+
properties: [
|
|
32
|
+
{ key: 'window_id', valueType: 'string', valueJson: JSON.stringify(input.windowId) },
|
|
33
|
+
...(input.opensAtMs !== undefined
|
|
34
|
+
? [{ key: 'opens_at_ms', valueType: 'int', valueJson: String(input.opensAtMs) }]
|
|
35
|
+
: []),
|
|
36
|
+
...(input.closesAtMs !== undefined
|
|
37
|
+
? [{ key: 'closes_at_ms', valueType: 'int', valueJson: String(input.closesAtMs) }]
|
|
38
|
+
: []),
|
|
39
|
+
{
|
|
40
|
+
key: 'modifiers',
|
|
41
|
+
valueType: 'string',
|
|
42
|
+
valueJson: JSON.stringify(JSON.stringify(input.modifiers ?? {})),
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** Every window (model read). */
|
|
48
|
+
async windows() {
|
|
49
|
+
const containers = await this.gameModel.containers({
|
|
50
|
+
appId: this.appId,
|
|
51
|
+
typeName: this.names.windowType,
|
|
52
|
+
});
|
|
53
|
+
return Promise.all(containers.map(async (c) => {
|
|
54
|
+
const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
|
|
55
|
+
let modifiers = {};
|
|
56
|
+
try {
|
|
57
|
+
modifiers = JSON.parse(String(props.modifiers ?? '{}'));
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
/* opaque */
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
containerId: c.containerId,
|
|
64
|
+
windowId: String(props.window_id ?? ''),
|
|
65
|
+
active: props.active === true,
|
|
66
|
+
opensAtMs: Number(props.opens_at_ms ?? 0),
|
|
67
|
+
closesAtMs: Number(props.closes_at_ms ?? 0),
|
|
68
|
+
modifiers,
|
|
69
|
+
};
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The ACTIVE windows. Engine path (scheduler deployed): the module's
|
|
74
|
+
* authoritative view; otherwise filters the model read.
|
|
75
|
+
*/
|
|
76
|
+
async activeWindows() {
|
|
77
|
+
if (this.engines && (await this.engineAvailable())) {
|
|
78
|
+
const result = await this.engines.invoke(this.moduleName, 'active_windows', {});
|
|
79
|
+
if (result.success && Array.isArray(result.body.windows)) {
|
|
80
|
+
const all = await this.windows();
|
|
81
|
+
const activeIds = new Set(result.body.windows.map((w) => String(w.windowId)));
|
|
82
|
+
return all.filter((w) => activeIds.has(w.windowId));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return (await this.windows()).filter((w) => w.active);
|
|
86
|
+
}
|
|
87
|
+
/** STUDIO (admin/automation) — open a window through the model function. */
|
|
88
|
+
async openWindow(windowContainerId, sessionId) {
|
|
89
|
+
return kitInvoke(this.gameModel, {
|
|
90
|
+
appId: String(this.appId),
|
|
91
|
+
functionName: this.names.openWindowFn,
|
|
92
|
+
selfContainerId: windowContainerId,
|
|
93
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/** STUDIO (admin/automation) — close a window through the model function. */
|
|
97
|
+
async closeWindow(windowContainerId, sessionId) {
|
|
98
|
+
return kitInvoke(this.gameModel, {
|
|
99
|
+
appId: String(this.appId),
|
|
100
|
+
functionName: this.names.closeWindowFn,
|
|
101
|
+
selfContainerId: windowContainerId,
|
|
102
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/** STUDIO (admin) — create a season (+ battle-pass composition). */
|
|
106
|
+
async defineSeason(input) {
|
|
107
|
+
return this.gameModel.createContainer({
|
|
108
|
+
appId: this.appId,
|
|
109
|
+
typeName: this.names.seasonType,
|
|
110
|
+
displayName: input.displayName ?? `Season ${input.seasonId}`,
|
|
111
|
+
properties: [
|
|
112
|
+
{ key: 'season_id', valueType: 'string', valueJson: JSON.stringify(input.seasonId) },
|
|
113
|
+
...(input.startsAtMs !== undefined
|
|
114
|
+
? [{ key: 'starts_at_ms', valueType: 'int', valueJson: String(input.startsAtMs) }]
|
|
115
|
+
: []),
|
|
116
|
+
...(input.endsAtMs !== undefined
|
|
117
|
+
? [{ key: 'ends_at_ms', valueType: 'int', valueJson: String(input.endsAtMs) }]
|
|
118
|
+
: []),
|
|
119
|
+
...(input.passTrack !== undefined
|
|
120
|
+
? [{ key: 'pass_track', valueType: 'string', valueJson: JSON.stringify(input.passTrack) }]
|
|
121
|
+
: []),
|
|
122
|
+
{
|
|
123
|
+
key: 'pass_features',
|
|
124
|
+
valueType: 'string',
|
|
125
|
+
valueJson: JSON.stringify(JSON.stringify(input.passFeatures ?? [])),
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/** Every season (model read). */
|
|
131
|
+
async seasons() {
|
|
132
|
+
const containers = await this.gameModel.containers({
|
|
133
|
+
appId: this.appId,
|
|
134
|
+
typeName: this.names.seasonType,
|
|
135
|
+
});
|
|
136
|
+
return Promise.all(containers.map(async (c) => {
|
|
137
|
+
const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
|
|
138
|
+
let passFeatures = [];
|
|
139
|
+
try {
|
|
140
|
+
passFeatures = JSON.parse(String(props.pass_features ?? '[]')).map(String);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
/* opaque */
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
containerId: c.containerId,
|
|
147
|
+
seasonId: String(props.season_id ?? ''),
|
|
148
|
+
active: props.active === true,
|
|
149
|
+
startsAtMs: Number(props.starts_at_ms ?? 0),
|
|
150
|
+
endsAtMs: Number(props.ends_at_ms ?? 0),
|
|
151
|
+
passTrack: String(props.pass_track ?? ''),
|
|
152
|
+
passFeatures,
|
|
153
|
+
};
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
/** The active season, when one exists. */
|
|
157
|
+
async currentSeason() {
|
|
158
|
+
return (await this.seasons()).find((s) => s.active) ?? null;
|
|
159
|
+
}
|
|
160
|
+
/** STUDIO (admin/automation) — activate a season through the model function. */
|
|
161
|
+
async activateSeason(seasonContainerId, sessionId) {
|
|
162
|
+
return kitInvoke(this.gameModel, {
|
|
163
|
+
appId: String(this.appId),
|
|
164
|
+
functionName: this.names.activateSeasonFn,
|
|
165
|
+
selfContainerId: seasonContainerId,
|
|
166
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/** Parse a type-98 zone-change server event (BR circles, event areas). */
|
|
170
|
+
parseZoneChange(bytes) {
|
|
171
|
+
const parsed = parseEngineEvent(bytes);
|
|
172
|
+
if (!parsed || parsed.eventType !== EVENT_ZONE_CHANGE)
|
|
173
|
+
return null;
|
|
174
|
+
return {
|
|
175
|
+
kind: String(parsed.body.kind ?? ''),
|
|
176
|
+
phase: parsed.body.phase != null ? Number(parsed.body.phase) : null,
|
|
177
|
+
radiusNow: Number(parsed.body.radiusNow ?? 0),
|
|
178
|
+
centerX: Number(parsed.body.centerX ?? 0),
|
|
179
|
+
centerZ: Number(parsed.body.centerZ ?? 0),
|
|
180
|
+
body: parsed.body,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
package/dist/kit/loot.d.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import type { GameModelAPI } from '../domains/gameModel.js';
|
|
2
|
+
import type { EngineDetector } from './engine.js';
|
|
2
3
|
import type { Scalars } from '../generated/graphql.js';
|
|
3
4
|
import { type KitInvokeResult } from './shared.js';
|
|
4
5
|
/** Options for {@link LootKit}. Must match the deployed loot blueprint. */
|
|
5
6
|
export interface LootKitOptions {
|
|
7
|
+
/**
|
|
8
|
+
* The big-table loot module (pity timers, audit trails). Defaults to
|
|
9
|
+
* `'loot-engine'`; the gacha-shrine example ships this contract.
|
|
10
|
+
*/
|
|
11
|
+
engineModuleName?: string;
|
|
6
12
|
/** The `typePrefix` the loot blueprint was deployed with. */
|
|
7
13
|
typePrefix?: string;
|
|
8
14
|
}
|
|
@@ -29,9 +35,24 @@ export interface KitLootRoll {
|
|
|
29
35
|
export declare class LootKit {
|
|
30
36
|
private readonly appId;
|
|
31
37
|
private readonly gameModel;
|
|
38
|
+
private readonly engines?;
|
|
32
39
|
private readonly names;
|
|
33
40
|
private readonly typePrefix;
|
|
34
|
-
constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: LootKitOptions);
|
|
41
|
+
constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: LootKitOptions, engines?: EngineDetector | undefined);
|
|
42
|
+
private readonly engineModuleName;
|
|
43
|
+
/**
|
|
44
|
+
* Is a big-table loot module deployed + enabled (cached per session)?
|
|
45
|
+
* When true, {@link enginePull} routes rolls through server-held RNG with
|
|
46
|
+
* pity timers + audit trails; the blueprint's weighted model rolls stay
|
|
47
|
+
* for small tables (the coexistence policy — "the server picks the path").
|
|
48
|
+
*/
|
|
49
|
+
engineAvailable(): Promise<boolean>;
|
|
50
|
+
/** Pull from the module's table (pity-timer path); count caps at 10. */
|
|
51
|
+
enginePull(count?: number): Promise<Record<string, unknown>>;
|
|
52
|
+
/** Your pity counters + roll totals from the module. */
|
|
53
|
+
enginePity(): Promise<Record<string, unknown>>;
|
|
54
|
+
/** Your rolling audit trail from the module (dispute resolution). */
|
|
55
|
+
engineAudit(): Promise<Record<string, unknown>>;
|
|
35
56
|
/**
|
|
36
57
|
* Create an unrolled `LootRoll` for a table, owned by `ownerUserId` (who
|
|
37
58
|
* will claim it). Event-drop automations pick from the pool of unrolled
|
package/dist/kit/loot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loot.d.ts","sourceRoot":"","sources":["../../src/kit/loot.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,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,qBAAa,OAAO;IAKhB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;
|
|
1
|
+
{"version":3,"file":"loot.d.ts","sourceRoot":"","sources":["../../src/kit/loot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAErB,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,qBAAa,OAAO;IAKhB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAP3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAGjB,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACjC,SAAS,EAAE,YAAY,EACxC,OAAO,GAAE,cAAmB,EACX,OAAO,CAAC,EAAE,cAAc,YAAA;IAO3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAE1C;;;;;OAKG;IACH,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAKnC,wEAAwE;IAClE,UAAU,CAAC,KAAK,SAAI;IAO1B,wDAAwD;IAClD,UAAU;IAOhB,qEAAqE;IAC/D,WAAW;IAOjB;;;;OAIG;IACG,UAAU,CAAC,KAAK,EAAE;QACtB,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC;QACxC,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;IAqBD;;;;;;OAMG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAU9E;;;;OAIG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAShF,6BAA6B;IACvB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAYjD;;;OAGG;IACG,KAAK,CACT,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACvC,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1D,OAAO,CAAC,WAAW,EAAE,CAAC;IAwBzB;;;OAGG;IACG,OAAO,CACX,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO;;;;;;;;;;;;;;;;;YAYtC,MAAM;CAoBrB"}
|
package/dist/kit/loot.js
CHANGED
|
@@ -10,11 +10,51 @@ import { kitContainerProperties, kitInvoke, } from './shared.js';
|
|
|
10
10
|
* Obtained via `client.kit(appId).loot`.
|
|
11
11
|
*/
|
|
12
12
|
export class LootKit {
|
|
13
|
-
constructor(appId, gameModel, options = {}) {
|
|
13
|
+
constructor(appId, gameModel, options = {}, engines) {
|
|
14
14
|
this.appId = appId;
|
|
15
15
|
this.gameModel = gameModel;
|
|
16
|
+
this.engines = engines;
|
|
16
17
|
this.typePrefix = options.typePrefix ?? '';
|
|
17
18
|
this.names = lootNames(this.typePrefix);
|
|
19
|
+
this.engineModuleName = options.engineModuleName ?? 'loot-engine';
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Is a big-table loot module deployed + enabled (cached per session)?
|
|
23
|
+
* When true, {@link enginePull} routes rolls through server-held RNG with
|
|
24
|
+
* pity timers + audit trails; the blueprint's weighted model rolls stay
|
|
25
|
+
* for small tables (the coexistence policy — "the server picks the path").
|
|
26
|
+
*/
|
|
27
|
+
engineAvailable() {
|
|
28
|
+
if (!this.engines)
|
|
29
|
+
return Promise.resolve(false);
|
|
30
|
+
return this.engines.has(this.engineModuleName);
|
|
31
|
+
}
|
|
32
|
+
/** Pull from the module's table (pity-timer path); count caps at 10. */
|
|
33
|
+
async enginePull(count = 1) {
|
|
34
|
+
if (!this.engines)
|
|
35
|
+
throw new Error('loot engine unavailable: compute domain not wired');
|
|
36
|
+
const result = await this.engines.invoke(this.engineModuleName, 'pull', { count });
|
|
37
|
+
if (!result.success)
|
|
38
|
+
throw new Error(`loot.pull failed: ${result.reason ?? 'unknown'}`);
|
|
39
|
+
return result.body;
|
|
40
|
+
}
|
|
41
|
+
/** Your pity counters + roll totals from the module. */
|
|
42
|
+
async enginePity() {
|
|
43
|
+
if (!this.engines)
|
|
44
|
+
throw new Error('loot engine unavailable: compute domain not wired');
|
|
45
|
+
const result = await this.engines.invoke(this.engineModuleName, 'pity', {});
|
|
46
|
+
if (!result.success)
|
|
47
|
+
throw new Error(`loot.pity failed: ${result.reason ?? 'unknown'}`);
|
|
48
|
+
return result.body;
|
|
49
|
+
}
|
|
50
|
+
/** Your rolling audit trail from the module (dispute resolution). */
|
|
51
|
+
async engineAudit() {
|
|
52
|
+
if (!this.engines)
|
|
53
|
+
throw new Error('loot engine unavailable: compute domain not wired');
|
|
54
|
+
const result = await this.engines.invoke(this.engineModuleName, 'audit', {});
|
|
55
|
+
if (!result.success)
|
|
56
|
+
throw new Error(`loot.audit failed: ${result.reason ?? 'unknown'}`);
|
|
57
|
+
return result.body;
|
|
18
58
|
}
|
|
19
59
|
/**
|
|
20
60
|
* Create an unrolled `LootRoll` for a table, owned by `ownerUserId` (who
|
package/dist/kit/matches.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { ChannelsAPI } from '../domains/channels.js';
|
|
2
|
+
import type { EngineDetector } from './engine.js';
|
|
2
3
|
import type { GameModelAPI } from '../domains/gameModel.js';
|
|
3
4
|
import type { UdpAPI } from '../domains/udp.js';
|
|
4
5
|
import type { Scalars } from '../generated/graphql.js';
|
|
5
6
|
import { type KitInvokeResult } from './shared.js';
|
|
6
7
|
/** Options for {@link MatchesKit}. Must match the deployed matches blueprint. */
|
|
7
8
|
export interface MatchesKitOptions {
|
|
9
|
+
/**
|
|
10
|
+
* The compute module driving server-side match lifecycle when the app
|
|
11
|
+
* runs an engine. Defaults to `'match-engine'`.
|
|
12
|
+
*/
|
|
13
|
+
engineModuleName?: string;
|
|
8
14
|
/** The `typePrefix` the matches blueprint was deployed with. */
|
|
9
15
|
typePrefix?: string;
|
|
10
16
|
/**
|
|
@@ -52,9 +58,11 @@ export declare class MatchesKit {
|
|
|
52
58
|
private readonly gameModel;
|
|
53
59
|
private readonly channels;
|
|
54
60
|
private readonly udp;
|
|
61
|
+
private readonly engines?;
|
|
55
62
|
private readonly names;
|
|
56
63
|
private readonly actorUuid;
|
|
57
|
-
|
|
64
|
+
private readonly engineModuleName;
|
|
65
|
+
constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, channels: ChannelsAPI | undefined, udp: UdpAPI | undefined, options?: MatchesKitOptions, engines?: EngineDetector | undefined);
|
|
58
66
|
private requireChannels;
|
|
59
67
|
private requireUdp;
|
|
60
68
|
/**
|
|
@@ -136,5 +144,29 @@ export declare class MatchesKit {
|
|
|
136
144
|
*/
|
|
137
145
|
onMatchChanged(match: KitMatch, callback: (match: KitMatch) => void): () => void;
|
|
138
146
|
private toMatch;
|
|
147
|
+
/**
|
|
148
|
+
* Is a match compute engine deployed + enabled (cached per session)? When
|
|
149
|
+
* true the engine owns transitions (ready checks, turn order + timeouts,
|
|
150
|
+
* authoritative scoring); the blueprint's creator-driven functions remain
|
|
151
|
+
* for model-only deployments.
|
|
152
|
+
*/
|
|
153
|
+
engineAvailable(): Promise<boolean>;
|
|
154
|
+
/**
|
|
155
|
+
* Declare ready on an engine match (a MatchMeta container id). The match
|
|
156
|
+
* starts server-side once every expected player is ready.
|
|
157
|
+
*/
|
|
158
|
+
engineReady(matchId: string): Promise<Record<string, unknown>>;
|
|
159
|
+
/** Submit your move (the engine validates the turn + resolves). */
|
|
160
|
+
engineSubmitMove(matchId: string, params?: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
161
|
+
/** Forfeit an engine match. */
|
|
162
|
+
engineForfeit(matchId: string): Promise<Record<string, unknown>>;
|
|
163
|
+
/** The engine's live view: turn holder, timers, standings, summary. */
|
|
164
|
+
engineStatus(matchId: string): Promise<Record<string, unknown>>;
|
|
165
|
+
/**
|
|
166
|
+
* Resolve a matchmaking proposal to the match the engine created for it
|
|
167
|
+
* (poll after everyone accepts; see `kit.matchmaking`).
|
|
168
|
+
*/
|
|
169
|
+
findByProposal(proposalId: string): Promise<string | null>;
|
|
170
|
+
private engineInvoke;
|
|
139
171
|
}
|
|
140
172
|
//# sourceMappingURL=matches.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matches.d.ts","sourceRoot":"","sources":["../../src/kit/matches.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAGvD,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAErB,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,kCAAkC;AAClC,MAAM,WAAW,QAAQ;IACvB,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,sCAAsC;AACtC,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,qBAAa,UAAU;
|
|
1
|
+
{"version":3,"file":"matches.d.ts","sourceRoot":"","sources":["../../src/kit/matches.ts"],"names":[],"mappings":"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"}
|
package/dist/kit/matches.js
CHANGED
|
@@ -12,12 +12,14 @@ import { kitContainerProperties, kitInvoke, } from './shared.js';
|
|
|
12
12
|
* Obtained via `client.kit(appId).matches`.
|
|
13
13
|
*/
|
|
14
14
|
export class MatchesKit {
|
|
15
|
-
constructor(appId, gameModel, channels, udp, options = {}) {
|
|
15
|
+
constructor(appId, gameModel, channels, udp, options = {}, engines) {
|
|
16
16
|
this.appId = appId;
|
|
17
17
|
this.gameModel = gameModel;
|
|
18
18
|
this.channels = channels;
|
|
19
19
|
this.udp = udp;
|
|
20
|
+
this.engines = engines;
|
|
20
21
|
this.names = matchesNames(options.typePrefix ?? '');
|
|
22
|
+
this.engineModuleName = options.engineModuleName ?? 'match-engine';
|
|
21
23
|
this.actorUuid = options.actorUuid ?? generateCrowdyUuid();
|
|
22
24
|
}
|
|
23
25
|
requireChannels() {
|
|
@@ -250,4 +252,57 @@ export class MatchesKit {
|
|
|
250
252
|
: {}),
|
|
251
253
|
};
|
|
252
254
|
}
|
|
255
|
+
// -- Engine path (Wave 2): server-driven lifecycle over the match engine --
|
|
256
|
+
/**
|
|
257
|
+
* Is a match compute engine deployed + enabled (cached per session)? When
|
|
258
|
+
* true the engine owns transitions (ready checks, turn order + timeouts,
|
|
259
|
+
* authoritative scoring); the blueprint's creator-driven functions remain
|
|
260
|
+
* for model-only deployments.
|
|
261
|
+
*/
|
|
262
|
+
engineAvailable() {
|
|
263
|
+
if (!this.engines)
|
|
264
|
+
return Promise.resolve(false);
|
|
265
|
+
return this.engines.has(this.engineModuleName);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Declare ready on an engine match (a MatchMeta container id). The match
|
|
269
|
+
* starts server-side once every expected player is ready.
|
|
270
|
+
*/
|
|
271
|
+
async engineReady(matchId) {
|
|
272
|
+
return this.engineInvoke('ready', { matchId });
|
|
273
|
+
}
|
|
274
|
+
/** Submit your move (the engine validates the turn + resolves). */
|
|
275
|
+
async engineSubmitMove(matchId, params = {}) {
|
|
276
|
+
return this.engineInvoke('submit_move', { matchId, ...params });
|
|
277
|
+
}
|
|
278
|
+
/** Forfeit an engine match. */
|
|
279
|
+
async engineForfeit(matchId) {
|
|
280
|
+
return this.engineInvoke('forfeit', { matchId });
|
|
281
|
+
}
|
|
282
|
+
/** The engine's live view: turn holder, timers, standings, summary. */
|
|
283
|
+
async engineStatus(matchId) {
|
|
284
|
+
return this.engineInvoke('status', { matchId });
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Resolve a matchmaking proposal to the match the engine created for it
|
|
288
|
+
* (poll after everyone accepts; see `kit.matchmaking`).
|
|
289
|
+
*/
|
|
290
|
+
async findByProposal(proposalId) {
|
|
291
|
+
if (!this.engines)
|
|
292
|
+
return null;
|
|
293
|
+
const result = await this.engines.invoke(this.engineModuleName, 'find_by_proposal', {
|
|
294
|
+
proposalId,
|
|
295
|
+
});
|
|
296
|
+
return result.success ? String(result.body.matchId ?? '') || null : null;
|
|
297
|
+
}
|
|
298
|
+
async engineInvoke(exportName, params) {
|
|
299
|
+
if (!this.engines) {
|
|
300
|
+
throw new Error('match engine unavailable: compute domain not wired');
|
|
301
|
+
}
|
|
302
|
+
const result = await this.engines.invoke(this.engineModuleName, exportName, params);
|
|
303
|
+
if (!result.success) {
|
|
304
|
+
throw new Error(`matches.${exportName} failed: ${result.reason ?? 'unknown'}`);
|
|
305
|
+
}
|
|
306
|
+
return result.body;
|
|
307
|
+
}
|
|
253
308
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Scalars } from '../generated/graphql.js';
|
|
2
|
+
import type { EngineDetector } from './engine.js';
|
|
3
|
+
/** Options for {@link MatchmakingKit}. */
|
|
4
|
+
export interface MatchmakingKitOptions {
|
|
5
|
+
/** The matchmaking module name. Defaults to `'matchmaking'`. */
|
|
6
|
+
moduleName?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Your queue status: where you are queued and any live proposal. */
|
|
9
|
+
export interface KitQueueStatus {
|
|
10
|
+
queuedIn: string | null;
|
|
11
|
+
proposal: {
|
|
12
|
+
proposalId: string;
|
|
13
|
+
mode: string;
|
|
14
|
+
players: string[];
|
|
15
|
+
accepted: string[];
|
|
16
|
+
handedOff: boolean;
|
|
17
|
+
} | null;
|
|
18
|
+
queueDepth: number;
|
|
19
|
+
rating: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Runtime helpers for the matchmaking engine (Wave 2): rating-bucketed
|
|
23
|
+
* queues with widening windows, party blocks, and accept-gated proposals
|
|
24
|
+
* that hand off to the match layer over compute events. After everyone
|
|
25
|
+
* accepts, resolve the created match with `kit.matches.findByProposal`.
|
|
26
|
+
*
|
|
27
|
+
* Obtained via `client.kit(appId).matchmaking`.
|
|
28
|
+
*/
|
|
29
|
+
export declare class MatchmakingKit {
|
|
30
|
+
private readonly engines;
|
|
31
|
+
private readonly moduleName;
|
|
32
|
+
constructor(_appId: Scalars['BigInt']['input'], engines: EngineDetector, options?: MatchmakingKitOptions);
|
|
33
|
+
/** Is the matchmaking engine deployed + enabled (cached per session)? */
|
|
34
|
+
engineAvailable(): Promise<boolean>;
|
|
35
|
+
/**
|
|
36
|
+
* Join a queue (optionally with a party block that must match together,
|
|
37
|
+
* and an explicit rating for games that keep rating on the progression
|
|
38
|
+
* layer).
|
|
39
|
+
*/
|
|
40
|
+
queueJoin(input?: {
|
|
41
|
+
mode?: string;
|
|
42
|
+
rating?: number;
|
|
43
|
+
party?: string[];
|
|
44
|
+
}): Promise<Record<string, unknown>>;
|
|
45
|
+
/** Leave your queue (all modes, or one with `mode`). */
|
|
46
|
+
queueLeave(mode?: string): Promise<Record<string, unknown>>;
|
|
47
|
+
/** Your queue/proposal status. */
|
|
48
|
+
queueStatus(mode?: string): Promise<KitQueueStatus>;
|
|
49
|
+
/** Accept a proposal; when everyone has, the match handoff fires. */
|
|
50
|
+
accept(proposalId: string): Promise<Record<string, unknown>>;
|
|
51
|
+
/** Report the decided result (Elo-lite rating update + proposal close). */
|
|
52
|
+
reportResult(proposalId: string, winnerUserId: string): Promise<Record<string, unknown>>;
|
|
53
|
+
/** Engine totals (queues/proposals/rated players). */
|
|
54
|
+
status(): Promise<Record<string, unknown>>;
|
|
55
|
+
private invoke;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=matchmaking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchmaking.d.ts","sourceRoot":"","sources":["../../src/kit/matchmaking.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE;QACR,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,SAAS,EAAE,OAAO,CAAC;KACpB,GAAG,IAAI,CAAC;IACT,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,qBAAa,cAAc;IAKvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAGlC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACjB,OAAO,EAAE,cAAc,EACxC,OAAO,GAAE,qBAA0B;IAKrC,yEAAyE;IACzE,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAInC;;;;OAIG;IACG,SAAS,CAAC,KAAK,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAO;IAIhF,wDAAwD;IAClD,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM;IAI9B,kCAAkC;IAC5B,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAUzD,qEAAqE;IAC/D,MAAM,CAAC,UAAU,EAAE,MAAM;IAI/B,2EAA2E;IACrE,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;IAI3D,sDAAsD;IAChD,MAAM;YAIE,MAAM;CAOrB"}
|