@crowdedkingdoms/crowdyjs 8.2.0 → 8.4.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 +81 -3
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +5 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/kit/blueprints/combat.d.ts +75 -0
- package/dist/kit/blueprints/combat.d.ts.map +1 -0
- package/dist/kit/blueprints/combat.js +351 -0
- package/dist/kit/blueprints/core.d.ts +222 -0
- package/dist/kit/blueprints/core.d.ts.map +1 -0
- package/dist/kit/blueprints/core.js +185 -0
- package/dist/kit/blueprints/decks.d.ts +50 -0
- package/dist/kit/blueprints/decks.d.ts.map +1 -0
- package/dist/kit/blueprints/decks.js +163 -0
- package/dist/kit/blueprints/economy.d.ts +88 -0
- package/dist/kit/blueprints/economy.d.ts.map +1 -0
- package/dist/kit/blueprints/economy.js +533 -0
- package/dist/kit/blueprints/guild.d.ts +51 -0
- package/dist/kit/blueprints/guild.d.ts.map +1 -0
- package/dist/kit/blueprints/guild.js +50 -0
- package/dist/kit/blueprints/index.d.ts +21 -0
- package/dist/kit/blueprints/index.d.ts.map +1 -0
- package/dist/kit/blueprints/index.js +20 -0
- package/dist/kit/blueprints/inventory.d.ts +38 -0
- package/dist/kit/blueprints/inventory.d.ts.map +1 -0
- package/dist/kit/blueprints/inventory.js +157 -0
- package/dist/kit/blueprints/leaderboards.d.ts +49 -0
- package/dist/kit/blueprints/leaderboards.d.ts.map +1 -0
- package/dist/kit/blueprints/leaderboards.js +126 -0
- package/dist/kit/blueprints/locks.d.ts +82 -0
- package/dist/kit/blueprints/locks.d.ts.map +1 -0
- package/dist/kit/blueprints/locks.js +155 -0
- package/dist/kit/blueprints/loot.d.ts +84 -0
- package/dist/kit/blueprints/loot.d.ts.map +1 -0
- package/dist/kit/blueprints/loot.js +228 -0
- package/dist/kit/blueprints/matches.d.ts +59 -0
- package/dist/kit/blueprints/matches.d.ts.map +1 -0
- package/dist/kit/blueprints/matches.js +246 -0
- package/dist/kit/blueprints/npcs.d.ts +71 -0
- package/dist/kit/blueprints/npcs.d.ts.map +1 -0
- package/dist/kit/blueprints/npcs.js +122 -0
- package/dist/kit/blueprints/plots.d.ts +54 -0
- package/dist/kit/blueprints/plots.d.ts.map +1 -0
- package/dist/kit/blueprints/plots.js +146 -0
- package/dist/kit/blueprints/progression.d.ts +68 -0
- package/dist/kit/blueprints/progression.d.ts.map +1 -0
- package/dist/kit/blueprints/progression.js +324 -0
- package/dist/kit/blueprints/quests.d.ts +65 -0
- package/dist/kit/blueprints/quests.d.ts.map +1 -0
- package/dist/kit/blueprints/quests.js +284 -0
- package/dist/kit/blueprints/worldsim.d.ts +84 -0
- package/dist/kit/blueprints/worldsim.d.ts.map +1 -0
- package/dist/kit/blueprints/worldsim.js +461 -0
- package/dist/kit/combat.d.ts +103 -0
- package/dist/kit/combat.d.ts.map +1 -0
- package/dist/kit/combat.js +151 -0
- package/dist/kit/decks.d.ts +123 -0
- package/dist/kit/decks.d.ts.map +1 -0
- package/dist/kit/decks.js +138 -0
- package/dist/kit/economy.d.ts +244 -0
- package/dist/kit/economy.d.ts.map +1 -0
- package/dist/kit/economy.js +365 -0
- package/dist/kit/features.d.ts +60 -0
- package/dist/kit/features.d.ts.map +1 -0
- package/dist/kit/features.js +65 -0
- package/dist/kit/index.d.ts +13 -2
- package/dist/kit/index.d.ts.map +1 -1
- package/dist/kit/index.js +12 -1
- package/dist/kit/inventory.d.ts +5 -0
- package/dist/kit/inventory.d.ts.map +1 -1
- package/dist/kit/inventory.js +14 -1
- package/dist/kit/kit.d.ts +58 -2
- package/dist/kit/kit.d.ts.map +1 -1
- package/dist/kit/kit.js +24 -2
- package/dist/kit/leaderboards.d.ts +66 -0
- package/dist/kit/leaderboards.d.ts.map +1 -0
- package/dist/kit/leaderboards.js +94 -0
- package/dist/kit/loot.d.ts +106 -0
- package/dist/kit/loot.d.ts.map +1 -0
- package/dist/kit/loot.js +120 -0
- package/dist/kit/matches.d.ts +140 -0
- package/dist/kit/matches.d.ts.map +1 -0
- package/dist/kit/matches.js +253 -0
- package/dist/kit/objects.js +1 -1
- package/dist/kit/plots.js +1 -1
- package/dist/kit/progression.d.ts +181 -0
- package/dist/kit/progression.d.ts.map +1 -0
- package/dist/kit/progression.js +265 -0
- package/dist/kit/quests.d.ts +110 -0
- package/dist/kit/quests.d.ts.map +1 -0
- package/dist/kit/quests.js +158 -0
- package/dist/kit/social.d.ts +267 -0
- package/dist/kit/social.d.ts.map +1 -0
- package/dist/kit/social.js +230 -0
- package/dist/kit/worldsim.d.ts +225 -0
- package/dist/kit/worldsim.d.ts.map +1 -0
- package/dist/kit/worldsim.js +231 -0
- package/dist/stores/actors.d.ts +316 -0
- package/dist/stores/actors.d.ts.map +1 -0
- package/dist/stores/actors.js +506 -0
- package/dist/stores/chunks.d.ts +180 -0
- package/dist/stores/chunks.d.ts.map +1 -0
- package/dist/stores/chunks.js +378 -0
- package/dist/stores/codec.d.ts +109 -0
- package/dist/stores/codec.d.ts.map +1 -0
- package/dist/stores/codec.js +186 -0
- package/dist/stores/durable.d.ts +144 -0
- package/dist/stores/durable.d.ts.map +1 -0
- package/dist/stores/durable.js +246 -0
- package/dist/stores/errors.d.ts +69 -0
- package/dist/stores/errors.d.ts.map +1 -0
- package/dist/stores/errors.js +87 -0
- package/dist/stores/inbox.d.ts +184 -0
- package/dist/stores/inbox.d.ts.map +1 -0
- package/dist/stores/inbox.js +326 -0
- package/dist/stores/index.d.ts +186 -0
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/index.js +109 -0
- package/dist/stores/keys.d.ts +52 -0
- package/dist/stores/keys.d.ts.map +1 -0
- package/dist/stores/keys.js +76 -0
- package/dist/stores/model.d.ts +81 -0
- package/dist/stores/model.d.ts.map +1 -0
- package/dist/stores/model.js +163 -0
- package/dist/stores/session.d.ts +119 -0
- package/dist/stores/session.d.ts.map +1 -0
- package/dist/stores/session.js +116 -0
- package/dist/stores/ticker.d.ts +44 -0
- package/dist/stores/ticker.d.ts.map +1 -0
- package/dist/stores/ticker.js +127 -0
- package/package.json +6 -1
- package/dist/kit/blueprints.d.ts +0 -370
- package/dist/kit/blueprints.d.ts.map +0 -1
- package/dist/kit/blueprints.js +0 -643
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { type KitBlueprint, type KitOwnerIdKind, type KitTrustedAuthority } from './core.js';
|
|
2
|
+
/** Options for {@link economyBlueprint}. */
|
|
3
|
+
export interface EconomyBlueprintOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Prefix applied to the container type names (`'Black'` → `BlackWallet` /
|
|
6
|
+
* `BlackShopListing` / …) and, snake-cased, to the function names
|
|
7
|
+
* (`black_earn_gold`, …). Lets several economies coexist. Defaults to none.
|
|
8
|
+
*/
|
|
9
|
+
typePrefix?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Currency property names on the wallet, one int property (default 0) per
|
|
12
|
+
* entry, each with `earn_<c>` / `spend_<c>` functions. Defaults to
|
|
13
|
+
* `['gold']`.
|
|
14
|
+
*/
|
|
15
|
+
currencies?: string[];
|
|
16
|
+
/**
|
|
17
|
+
* The wallet currency shops and market listings are priced in. Defaults to
|
|
18
|
+
* the first entry of `currencies`. (Expressions cannot pick a wallet
|
|
19
|
+
* property dynamically, so one deployment trades in one currency; deploy a
|
|
20
|
+
* prefixed second blueprint for a second shop currency.)
|
|
21
|
+
*/
|
|
22
|
+
shopCurrency?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Who may mint currency via `earn_<c>`. Trusted grants should be `'server'`
|
|
25
|
+
* (app admins / studio backend, the default), `'host'`, or
|
|
26
|
+
* `'automation'` — never plain players. Defaults to `'server'`.
|
|
27
|
+
*/
|
|
28
|
+
earnAuthority?: KitTrustedAuthority;
|
|
29
|
+
/**
|
|
30
|
+
* How `owner_user_id` mirrors are typed on the stack containers this
|
|
31
|
+
* economy guards (see the kit owner-mirroring convention). Defaults to
|
|
32
|
+
* `'int'` (the kit standard).
|
|
33
|
+
*/
|
|
34
|
+
ownerIdKind?: KitOwnerIdKind;
|
|
35
|
+
/**
|
|
36
|
+
* When set, adds a `restock_listing` automation that periodically raises
|
|
37
|
+
* every listing's `stock` (by `amount`, clamped to `max_stock`) — the NPC
|
|
38
|
+
* trader restock pattern.
|
|
39
|
+
*/
|
|
40
|
+
restock?: {
|
|
41
|
+
intervalMs: number;
|
|
42
|
+
amount?: number;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Names derived by {@link economyBlueprint} for a given prefix. */
|
|
46
|
+
export interface EconomyNames {
|
|
47
|
+
walletType: string;
|
|
48
|
+
listingType: string;
|
|
49
|
+
tradeType: string;
|
|
50
|
+
marketType: string;
|
|
51
|
+
/** Snake-cased function-name prefix (empty without a `typePrefix`). */
|
|
52
|
+
fnPrefix: string;
|
|
53
|
+
buyListingFn: string;
|
|
54
|
+
acceptTradeFn: string;
|
|
55
|
+
cancelTradeFn: string;
|
|
56
|
+
buyMarketFn: string;
|
|
57
|
+
cancelMarketFn: string;
|
|
58
|
+
restockFn: string;
|
|
59
|
+
restockAutomation: string;
|
|
60
|
+
}
|
|
61
|
+
/** Compute the type/function names an economy blueprint (and its runtime helper) uses. */
|
|
62
|
+
export declare function economyNames(typePrefix?: string): EconomyNames;
|
|
63
|
+
/** The earn/spend function name for one currency. */
|
|
64
|
+
export declare function economyCurrencyFn(verb: 'earn' | 'spend', currency: string, typePrefix?: string): string;
|
|
65
|
+
/**
|
|
66
|
+
* Blueprint for a server-authoritative **economy**: per-player `Wallet`
|
|
67
|
+
* containers (one int property per currency), an admin `ShopListing` catalog
|
|
68
|
+
* with an atomic `buy_listing` (wallet debit + stock decrement + item grant
|
|
69
|
+
* in ONE invoke), escrow `TradeOffer` swaps, and a player-to-player
|
|
70
|
+
* `MarketListing` flow (buyer wallet → seller wallet + stack transfer, all
|
|
71
|
+
* in one transaction).
|
|
72
|
+
*
|
|
73
|
+
* Anti-duplication is structural: every movement of currency or items is a
|
|
74
|
+
* single function invocation whose condition guards check balances, stock,
|
|
75
|
+
* item identity, and ownership mirrors server-side — never split a spend and
|
|
76
|
+
* a grant across two invokes. Trusted mints (`earn_<c>`) default to
|
|
77
|
+
* `invokeScope: "server"` (app admins only).
|
|
78
|
+
*
|
|
79
|
+
* Trade/market guards verify stack ownership through the kit-standard
|
|
80
|
+
* `owner_user_id` mirror property on the stack type (the inventory blueprint
|
|
81
|
+
* defines it; set it via `InventoryKit.createStack({ ownerUserId })`), and
|
|
82
|
+
* pin the offer creator via the injected `$self_owner_id` — the server-truth
|
|
83
|
+
* owner of the offer/listing container.
|
|
84
|
+
*
|
|
85
|
+
* Runtime counterpart: `client.kit(appId).economy`.
|
|
86
|
+
*/
|
|
87
|
+
export declare function economyBlueprint(options?: EconomyBlueprintOptions): KitBlueprint;
|
|
88
|
+
//# sourceMappingURL=economy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"economy.d.ts","sourceRoot":"","sources":["../../../src/kit/blueprints/economy.ts"],"names":[],"mappings":"AAIA,OAAO,EAQL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACzB,MAAM,WAAW,CAAC;AAEnB,4CAA4C;AAC5C,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC;;;;OAIG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACnD;AAED,oEAAoE;AACpE,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,UAAU,SAAK,GAAG,YAAY,CAgB1D;AAED,qDAAqD;AACrD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,GAAG,OAAO,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,SAAK,GACd,MAAM,CAGR;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,uBAA4B,GACpC,YAAY,CAyfd"}
|
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import { kitPolicyJson, ownerEquals, ownerEqualsCaller, ownerMirrorProperty, toSnakeCase, trustedAuthorityFields, } from './core.js';
|
|
2
|
+
/** Compute the type/function names an economy blueprint (and its runtime helper) uses. */
|
|
3
|
+
export function economyNames(typePrefix = '') {
|
|
4
|
+
const fnPrefix = typePrefix ? `${toSnakeCase(typePrefix)}_` : '';
|
|
5
|
+
return {
|
|
6
|
+
walletType: `${typePrefix}Wallet`,
|
|
7
|
+
listingType: `${typePrefix}ShopListing`,
|
|
8
|
+
tradeType: `${typePrefix}TradeOffer`,
|
|
9
|
+
marketType: `${typePrefix}MarketListing`,
|
|
10
|
+
fnPrefix,
|
|
11
|
+
buyListingFn: `${fnPrefix}buy_listing`,
|
|
12
|
+
acceptTradeFn: `${fnPrefix}accept_trade`,
|
|
13
|
+
cancelTradeFn: `${fnPrefix}cancel_trade`,
|
|
14
|
+
buyMarketFn: `${fnPrefix}buy_market_listing`,
|
|
15
|
+
cancelMarketFn: `${fnPrefix}cancel_market_listing`,
|
|
16
|
+
restockFn: `${fnPrefix}restock_listing`,
|
|
17
|
+
restockAutomation: `${fnPrefix.replace(/_/g, '-')}shop-restock`,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** The earn/spend function name for one currency. */
|
|
21
|
+
export function economyCurrencyFn(verb, currency, typePrefix = '') {
|
|
22
|
+
const fnPrefix = typePrefix ? `${toSnakeCase(typePrefix)}_` : '';
|
|
23
|
+
return `${fnPrefix}${verb}_${toSnakeCase(currency)}`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Blueprint for a server-authoritative **economy**: per-player `Wallet`
|
|
27
|
+
* containers (one int property per currency), an admin `ShopListing` catalog
|
|
28
|
+
* with an atomic `buy_listing` (wallet debit + stock decrement + item grant
|
|
29
|
+
* in ONE invoke), escrow `TradeOffer` swaps, and a player-to-player
|
|
30
|
+
* `MarketListing` flow (buyer wallet → seller wallet + stack transfer, all
|
|
31
|
+
* in one transaction).
|
|
32
|
+
*
|
|
33
|
+
* Anti-duplication is structural: every movement of currency or items is a
|
|
34
|
+
* single function invocation whose condition guards check balances, stock,
|
|
35
|
+
* item identity, and ownership mirrors server-side — never split a spend and
|
|
36
|
+
* a grant across two invokes. Trusted mints (`earn_<c>`) default to
|
|
37
|
+
* `invokeScope: "server"` (app admins only).
|
|
38
|
+
*
|
|
39
|
+
* Trade/market guards verify stack ownership through the kit-standard
|
|
40
|
+
* `owner_user_id` mirror property on the stack type (the inventory blueprint
|
|
41
|
+
* defines it; set it via `InventoryKit.createStack({ ownerUserId })`), and
|
|
42
|
+
* pin the offer creator via the injected `$self_owner_id` — the server-truth
|
|
43
|
+
* owner of the offer/listing container.
|
|
44
|
+
*
|
|
45
|
+
* Runtime counterpart: `client.kit(appId).economy`.
|
|
46
|
+
*/
|
|
47
|
+
export function economyBlueprint(options = {}) {
|
|
48
|
+
const { typePrefix = '', currencies = ['gold'], ownerIdKind = 'int', earnAuthority = 'server', } = options;
|
|
49
|
+
if (currencies.length === 0) {
|
|
50
|
+
throw new Error('economyBlueprint requires at least one currency');
|
|
51
|
+
}
|
|
52
|
+
const currency = options.shopCurrency ?? currencies[0];
|
|
53
|
+
if (!currencies.includes(currency)) {
|
|
54
|
+
throw new Error(`economyBlueprint shopCurrency '${currency}' must be one of the declared currencies`);
|
|
55
|
+
}
|
|
56
|
+
const names = economyNames(typePrefix);
|
|
57
|
+
const kind = ownerIdKind;
|
|
58
|
+
const propertyDefinitions = [
|
|
59
|
+
// Wallet: owner mirror + one balance property per currency.
|
|
60
|
+
ownerMirrorProperty(names.walletType, kind),
|
|
61
|
+
...currencies.map((c) => ({
|
|
62
|
+
containerTypeName: names.walletType,
|
|
63
|
+
key: c,
|
|
64
|
+
valueType: 'int',
|
|
65
|
+
defaultValueJson: '0',
|
|
66
|
+
description: `Balance of the '${c}' currency.`,
|
|
67
|
+
})),
|
|
68
|
+
// Shop listing catalog row.
|
|
69
|
+
{
|
|
70
|
+
containerTypeName: names.listingType,
|
|
71
|
+
key: 'item_id',
|
|
72
|
+
valueType: 'string',
|
|
73
|
+
description: 'The item this listing sells (matched against stack item_id).',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
containerTypeName: names.listingType,
|
|
77
|
+
key: 'price',
|
|
78
|
+
valueType: 'int',
|
|
79
|
+
defaultValueJson: '0',
|
|
80
|
+
description: `Price per unit in '${currency}'.`,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
containerTypeName: names.listingType,
|
|
84
|
+
key: 'stock',
|
|
85
|
+
valueType: 'int',
|
|
86
|
+
defaultValueJson: '0',
|
|
87
|
+
description: 'Units remaining; buying decrements atomically.',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
containerTypeName: names.listingType,
|
|
91
|
+
key: 'max_stock',
|
|
92
|
+
valueType: 'int',
|
|
93
|
+
defaultValueJson: '0',
|
|
94
|
+
description: 'Restock ceiling used by the shop-restock automation.',
|
|
95
|
+
},
|
|
96
|
+
// Escrow trade offer.
|
|
97
|
+
{
|
|
98
|
+
containerTypeName: names.tradeType,
|
|
99
|
+
key: 'to_user_id',
|
|
100
|
+
valueType: 'int',
|
|
101
|
+
defaultValueJson: '0',
|
|
102
|
+
description: 'The user invited to accept this trade.',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
containerTypeName: names.tradeType,
|
|
106
|
+
key: 'give_stack_id',
|
|
107
|
+
valueType: 'string',
|
|
108
|
+
defaultValueJson: '""',
|
|
109
|
+
description: "Container id of the offerer's escrowed source stack.",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
containerTypeName: names.tradeType,
|
|
113
|
+
key: 'receive_stack_id',
|
|
114
|
+
valueType: 'string',
|
|
115
|
+
defaultValueJson: '""',
|
|
116
|
+
description: "Container id of the offerer's stack that receives the wanted items.",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
containerTypeName: names.tradeType,
|
|
120
|
+
key: 'give_item_id',
|
|
121
|
+
valueType: 'string',
|
|
122
|
+
defaultValueJson: '""',
|
|
123
|
+
description: 'Item the offerer gives.',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
containerTypeName: names.tradeType,
|
|
127
|
+
key: 'give_qty',
|
|
128
|
+
valueType: 'int',
|
|
129
|
+
defaultValueJson: '0',
|
|
130
|
+
description: 'Quantity the offerer gives.',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
containerTypeName: names.tradeType,
|
|
134
|
+
key: 'want_item_id',
|
|
135
|
+
valueType: 'string',
|
|
136
|
+
defaultValueJson: '""',
|
|
137
|
+
description: 'Item the offerer wants in return.',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
containerTypeName: names.tradeType,
|
|
141
|
+
key: 'want_qty',
|
|
142
|
+
valueType: 'int',
|
|
143
|
+
defaultValueJson: '0',
|
|
144
|
+
description: 'Quantity the offerer wants in return.',
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
containerTypeName: names.tradeType,
|
|
148
|
+
key: 'status',
|
|
149
|
+
valueType: 'string',
|
|
150
|
+
defaultValueJson: '"open"',
|
|
151
|
+
description: "Trade lifecycle: 'open' | 'accepted' | 'cancelled'.",
|
|
152
|
+
},
|
|
153
|
+
// Market listing.
|
|
154
|
+
{
|
|
155
|
+
containerTypeName: names.marketType,
|
|
156
|
+
key: 'stack_id',
|
|
157
|
+
valueType: 'string',
|
|
158
|
+
defaultValueJson: '""',
|
|
159
|
+
description: "Container id of the seller's escrowed source stack.",
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
containerTypeName: names.marketType,
|
|
163
|
+
key: 'item_id',
|
|
164
|
+
valueType: 'string',
|
|
165
|
+
defaultValueJson: '""',
|
|
166
|
+
description: 'Item being sold.',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
containerTypeName: names.marketType,
|
|
170
|
+
key: 'quantity',
|
|
171
|
+
valueType: 'int',
|
|
172
|
+
defaultValueJson: '0',
|
|
173
|
+
description: 'Units transferred to the buyer on purchase.',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
containerTypeName: names.marketType,
|
|
177
|
+
key: 'price',
|
|
178
|
+
valueType: 'int',
|
|
179
|
+
defaultValueJson: '0',
|
|
180
|
+
description: `Ask price in '${currency}' paid straight into the seller's wallet.`,
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
containerTypeName: names.marketType,
|
|
184
|
+
key: 'active',
|
|
185
|
+
valueType: 'bool',
|
|
186
|
+
defaultValueJson: 'true',
|
|
187
|
+
description: 'False once bought or cancelled.',
|
|
188
|
+
},
|
|
189
|
+
];
|
|
190
|
+
const functions = [];
|
|
191
|
+
// earn/spend per currency.
|
|
192
|
+
for (const c of currencies) {
|
|
193
|
+
functions.push({
|
|
194
|
+
name: economyCurrencyFn('earn', c, typePrefix),
|
|
195
|
+
containerTypeName: names.walletType,
|
|
196
|
+
returnType: 'int',
|
|
197
|
+
parameters: [
|
|
198
|
+
{
|
|
199
|
+
name: 'amount',
|
|
200
|
+
valueType: 'int',
|
|
201
|
+
required: true,
|
|
202
|
+
description: 'Units to add (negative values are ignored).',
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
mutations: [
|
|
206
|
+
{ target: 'self', property: c, expression: `self.${c} + max(0, $amount)` },
|
|
207
|
+
],
|
|
208
|
+
returnExpression: `self.${c}`,
|
|
209
|
+
...trustedAuthorityFields(earnAuthority),
|
|
210
|
+
description: `Mint '${c}' into this wallet — a trusted grant (default: app admins via server scope).`,
|
|
211
|
+
});
|
|
212
|
+
functions.push({
|
|
213
|
+
name: economyCurrencyFn('spend', c, typePrefix),
|
|
214
|
+
containerTypeName: names.walletType,
|
|
215
|
+
returnType: 'int',
|
|
216
|
+
parameters: [
|
|
217
|
+
{
|
|
218
|
+
name: 'amount',
|
|
219
|
+
valueType: 'int',
|
|
220
|
+
required: true,
|
|
221
|
+
description: 'Units to deduct; must not exceed the balance.',
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
mutations: [
|
|
225
|
+
{ target: 'self', property: c, expression: `self.${c} - $amount` },
|
|
226
|
+
],
|
|
227
|
+
returnExpression: `self.${c}`,
|
|
228
|
+
invokePolicyJson: kitPolicyJson({
|
|
229
|
+
type: 'and',
|
|
230
|
+
rules: [
|
|
231
|
+
{ type: 'owner_of_self' },
|
|
232
|
+
{
|
|
233
|
+
type: 'condition',
|
|
234
|
+
expression: `$amount > 0 && self.${c} >= $amount`,
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
}),
|
|
238
|
+
description: `Spend '${c}' from the caller's own wallet; refuses to overdraw.`,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
// Shop: atomic wallet debit + stock decrement + item grant.
|
|
242
|
+
functions.push({
|
|
243
|
+
name: names.buyListingFn,
|
|
244
|
+
containerTypeName: names.listingType,
|
|
245
|
+
returnType: 'int',
|
|
246
|
+
parameters: [
|
|
247
|
+
{
|
|
248
|
+
name: 'wallet_id',
|
|
249
|
+
valueType: 'container_ref',
|
|
250
|
+
required: true,
|
|
251
|
+
description: "The buyer's wallet (must be owned by the caller).",
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: 'to_stack_id',
|
|
255
|
+
valueType: 'container_ref',
|
|
256
|
+
required: true,
|
|
257
|
+
description: 'A stack of the listed item that receives the unit.',
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
mutations: [
|
|
261
|
+
{
|
|
262
|
+
target: 'ref($wallet_id)',
|
|
263
|
+
property: currency,
|
|
264
|
+
expression: `ref($wallet_id).${currency} - self.price`,
|
|
265
|
+
},
|
|
266
|
+
{ target: 'self', property: 'stock', expression: 'self.stock - 1' },
|
|
267
|
+
{
|
|
268
|
+
target: 'ref($to_stack_id)',
|
|
269
|
+
property: 'quantity',
|
|
270
|
+
expression: 'ref($to_stack_id).quantity + 1',
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
returnExpression: `ref($wallet_id).${currency}`,
|
|
274
|
+
invokePolicyJson: kitPolicyJson({
|
|
275
|
+
type: 'condition',
|
|
276
|
+
expression: [
|
|
277
|
+
'self.stock > 0',
|
|
278
|
+
ownerEqualsCaller('ref($wallet_id).owner_user_id', kind),
|
|
279
|
+
`ref($wallet_id).${currency} >= self.price`,
|
|
280
|
+
'ref($to_stack_id).item_id == self.item_id',
|
|
281
|
+
].join(' && '),
|
|
282
|
+
}),
|
|
283
|
+
description: 'Buy one unit: wallet debit, stock decrement, and item grant in one transaction — money duplication is structurally impossible.',
|
|
284
|
+
});
|
|
285
|
+
// Escrow trade: atomic four-stack swap. $self_owner_id (injected,
|
|
286
|
+
// unspoofable) is the offer creator, so a forged offer cannot drain a
|
|
287
|
+
// third party's stacks.
|
|
288
|
+
functions.push({
|
|
289
|
+
name: names.acceptTradeFn,
|
|
290
|
+
containerTypeName: names.tradeType,
|
|
291
|
+
returnType: 'string',
|
|
292
|
+
parameters: [
|
|
293
|
+
{
|
|
294
|
+
name: 'give_stack_id',
|
|
295
|
+
valueType: 'container_ref',
|
|
296
|
+
required: true,
|
|
297
|
+
description: "The offerer's escrowed source stack (must match the recorded give_stack_id).",
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: 'to_give_stack_id',
|
|
301
|
+
valueType: 'container_ref',
|
|
302
|
+
required: true,
|
|
303
|
+
description: "The acceptor's stack that receives the given items.",
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
name: 'want_stack_id',
|
|
307
|
+
valueType: 'container_ref',
|
|
308
|
+
required: true,
|
|
309
|
+
description: "The acceptor's stack that pays the wanted items.",
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
name: 'to_want_stack_id',
|
|
313
|
+
valueType: 'container_ref',
|
|
314
|
+
required: true,
|
|
315
|
+
description: "The offerer's stack that receives the wanted items (must match the recorded receive_stack_id).",
|
|
316
|
+
},
|
|
317
|
+
],
|
|
318
|
+
mutations: [
|
|
319
|
+
{
|
|
320
|
+
target: 'ref($give_stack_id)',
|
|
321
|
+
property: 'quantity',
|
|
322
|
+
expression: 'ref($give_stack_id).quantity - self.give_qty',
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
target: 'ref($to_give_stack_id)',
|
|
326
|
+
property: 'quantity',
|
|
327
|
+
expression: 'ref($to_give_stack_id).quantity + self.give_qty',
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
target: 'ref($want_stack_id)',
|
|
331
|
+
property: 'quantity',
|
|
332
|
+
expression: 'ref($want_stack_id).quantity - self.want_qty',
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
target: 'ref($to_want_stack_id)',
|
|
336
|
+
property: 'quantity',
|
|
337
|
+
expression: 'ref($to_want_stack_id).quantity + self.want_qty',
|
|
338
|
+
},
|
|
339
|
+
{ target: 'self', property: 'status', expression: '"accepted"' },
|
|
340
|
+
],
|
|
341
|
+
returnExpression: 'self.status',
|
|
342
|
+
invokePolicyJson: kitPolicyJson({
|
|
343
|
+
type: 'condition',
|
|
344
|
+
expression: [
|
|
345
|
+
'self.status == "open"',
|
|
346
|
+
'self.to_user_id == $caller_user_id',
|
|
347
|
+
'$give_stack_id == self.give_stack_id',
|
|
348
|
+
'$to_want_stack_id == self.receive_stack_id',
|
|
349
|
+
ownerEquals('ref($give_stack_id).owner_user_id', '$self_owner_id', kind),
|
|
350
|
+
'ref($give_stack_id).item_id == self.give_item_id',
|
|
351
|
+
'ref($give_stack_id).quantity >= self.give_qty',
|
|
352
|
+
ownerEqualsCaller('ref($to_give_stack_id).owner_user_id', kind),
|
|
353
|
+
'ref($to_give_stack_id).item_id == self.give_item_id',
|
|
354
|
+
ownerEqualsCaller('ref($want_stack_id).owner_user_id', kind),
|
|
355
|
+
'ref($want_stack_id).item_id == self.want_item_id',
|
|
356
|
+
'ref($want_stack_id).quantity >= self.want_qty',
|
|
357
|
+
ownerEquals('ref($to_want_stack_id).owner_user_id', '$self_owner_id', kind),
|
|
358
|
+
'ref($to_want_stack_id).item_id == self.want_item_id',
|
|
359
|
+
].join(' && '),
|
|
360
|
+
}),
|
|
361
|
+
description: 'Accept an escrow trade: both stack pairs swap atomically after ownership/item/quantity guards; any failure rolls the whole swap back.',
|
|
362
|
+
});
|
|
363
|
+
functions.push({
|
|
364
|
+
name: names.cancelTradeFn,
|
|
365
|
+
containerTypeName: names.tradeType,
|
|
366
|
+
returnType: 'string',
|
|
367
|
+
mutations: [{ target: 'self', property: 'status', expression: '"cancelled"' }],
|
|
368
|
+
returnExpression: 'self.status',
|
|
369
|
+
invokePolicyJson: kitPolicyJson({
|
|
370
|
+
type: 'condition',
|
|
371
|
+
expression: 'self.status == "open" && ($self_owner_id == $caller_user_id || self.to_user_id == $caller_user_id)',
|
|
372
|
+
}),
|
|
373
|
+
description: 'Cancel an open trade (either party may).',
|
|
374
|
+
});
|
|
375
|
+
// Market: wallet→wallet payment + stack transfer, one invoke, 5 mutations.
|
|
376
|
+
functions.push({
|
|
377
|
+
name: names.buyMarketFn,
|
|
378
|
+
containerTypeName: names.marketType,
|
|
379
|
+
returnType: 'int',
|
|
380
|
+
parameters: [
|
|
381
|
+
{
|
|
382
|
+
name: 'wallet_id',
|
|
383
|
+
valueType: 'container_ref',
|
|
384
|
+
required: true,
|
|
385
|
+
description: "The buyer's wallet (must be owned by the caller).",
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
name: 'seller_wallet_id',
|
|
389
|
+
valueType: 'container_ref',
|
|
390
|
+
required: true,
|
|
391
|
+
description: "The seller's wallet that receives the payment.",
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
name: 'from_stack_id',
|
|
395
|
+
valueType: 'container_ref',
|
|
396
|
+
required: true,
|
|
397
|
+
description: "The seller's escrowed source stack (must match the recorded stack_id).",
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
name: 'to_stack_id',
|
|
401
|
+
valueType: 'container_ref',
|
|
402
|
+
required: true,
|
|
403
|
+
description: "The buyer's stack that receives the items.",
|
|
404
|
+
},
|
|
405
|
+
],
|
|
406
|
+
mutations: [
|
|
407
|
+
{
|
|
408
|
+
target: 'ref($wallet_id)',
|
|
409
|
+
property: currency,
|
|
410
|
+
expression: `ref($wallet_id).${currency} - self.price`,
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
target: 'ref($seller_wallet_id)',
|
|
414
|
+
property: currency,
|
|
415
|
+
expression: `ref($seller_wallet_id).${currency} + self.price`,
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
target: 'ref($from_stack_id)',
|
|
419
|
+
property: 'quantity',
|
|
420
|
+
expression: 'ref($from_stack_id).quantity - self.quantity',
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
target: 'ref($to_stack_id)',
|
|
424
|
+
property: 'quantity',
|
|
425
|
+
expression: 'ref($to_stack_id).quantity + self.quantity',
|
|
426
|
+
},
|
|
427
|
+
{ target: 'self', property: 'active', expression: 'false' },
|
|
428
|
+
],
|
|
429
|
+
returnExpression: `ref($wallet_id).${currency}`,
|
|
430
|
+
invokePolicyJson: kitPolicyJson({
|
|
431
|
+
type: 'condition',
|
|
432
|
+
expression: [
|
|
433
|
+
'self.active',
|
|
434
|
+
ownerEqualsCaller('ref($wallet_id).owner_user_id', kind),
|
|
435
|
+
`ref($wallet_id).${currency} >= self.price`,
|
|
436
|
+
ownerEquals('ref($seller_wallet_id).owner_user_id', '$self_owner_id', kind),
|
|
437
|
+
'$from_stack_id == self.stack_id',
|
|
438
|
+
ownerEquals('ref($from_stack_id).owner_user_id', '$self_owner_id', kind),
|
|
439
|
+
'ref($from_stack_id).item_id == self.item_id',
|
|
440
|
+
'ref($from_stack_id).quantity >= self.quantity',
|
|
441
|
+
ownerEqualsCaller('ref($to_stack_id).owner_user_id', kind),
|
|
442
|
+
'ref($to_stack_id).item_id == self.item_id',
|
|
443
|
+
].join(' && '),
|
|
444
|
+
}),
|
|
445
|
+
description: "Buy a market listing: buyer wallet → seller wallet payment plus the stack transfer, all atomic; the listing deactivates in the same transaction.",
|
|
446
|
+
});
|
|
447
|
+
functions.push({
|
|
448
|
+
name: names.cancelMarketFn,
|
|
449
|
+
containerTypeName: names.marketType,
|
|
450
|
+
returnType: 'bool',
|
|
451
|
+
mutations: [{ target: 'self', property: 'active', expression: 'false' }],
|
|
452
|
+
returnExpression: 'self.active',
|
|
453
|
+
invokePolicyJson: kitPolicyJson({
|
|
454
|
+
type: 'condition',
|
|
455
|
+
expression: 'self.active && $self_owner_id == $caller_user_id',
|
|
456
|
+
}),
|
|
457
|
+
description: 'Take a market listing down (seller only).',
|
|
458
|
+
});
|
|
459
|
+
const automations = [];
|
|
460
|
+
if (options.restock) {
|
|
461
|
+
functions.push({
|
|
462
|
+
name: names.restockFn,
|
|
463
|
+
containerTypeName: names.listingType,
|
|
464
|
+
returnType: 'int',
|
|
465
|
+
parameters: [
|
|
466
|
+
{
|
|
467
|
+
name: 'amount',
|
|
468
|
+
valueType: 'int',
|
|
469
|
+
required: true,
|
|
470
|
+
description: 'Units to add per tick (clamped to max_stock).',
|
|
471
|
+
},
|
|
472
|
+
],
|
|
473
|
+
mutations: [
|
|
474
|
+
{
|
|
475
|
+
target: 'self',
|
|
476
|
+
property: 'stock',
|
|
477
|
+
expression: 'min(self.max_stock, self.stock + max(0, $amount))',
|
|
478
|
+
},
|
|
479
|
+
],
|
|
480
|
+
returnExpression: 'self.stock',
|
|
481
|
+
invokePolicyJson: kitPolicyJson({ type: 'is_automation' }),
|
|
482
|
+
autonomousInvocable: true,
|
|
483
|
+
description: 'Server-driven shop restock tick (automation-only).',
|
|
484
|
+
});
|
|
485
|
+
automations.push({
|
|
486
|
+
name: names.restockAutomation,
|
|
487
|
+
functionName: names.restockFn,
|
|
488
|
+
targetMode: 'type',
|
|
489
|
+
targetTypeName: names.listingType,
|
|
490
|
+
triggerType: 'schedule',
|
|
491
|
+
scheduleKind: 'interval',
|
|
492
|
+
intervalMs: options.restock.intervalMs,
|
|
493
|
+
maxTargets: 32,
|
|
494
|
+
selectorJson: JSON.stringify({
|
|
495
|
+
selfWhere: [{ key: 'stock', op: '<', value: 'self.max_stock' }],
|
|
496
|
+
}),
|
|
497
|
+
paramsJson: JSON.stringify({ amount: options.restock.amount ?? 1 }),
|
|
498
|
+
description: 'Periodically restocks shop listings below their max_stock.',
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
return {
|
|
502
|
+
name: names.walletType,
|
|
503
|
+
containerTypes: [
|
|
504
|
+
{
|
|
505
|
+
typeName: names.walletType,
|
|
506
|
+
displayName: names.walletType,
|
|
507
|
+
instantiableBy: 'member',
|
|
508
|
+
description: 'A per-player wallet holding currency balances.',
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
typeName: names.listingType,
|
|
512
|
+
displayName: names.listingType,
|
|
513
|
+
instantiableBy: 'admin',
|
|
514
|
+
description: 'A studio-priced shop listing (catalog row) players buy from.',
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
typeName: names.tradeType,
|
|
518
|
+
displayName: names.tradeType,
|
|
519
|
+
instantiableBy: 'member',
|
|
520
|
+
description: 'A player-to-player escrow trade offer, swapped atomically on accept.',
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
typeName: names.marketType,
|
|
524
|
+
displayName: names.marketType,
|
|
525
|
+
instantiableBy: 'member',
|
|
526
|
+
description: 'A player market listing paid straight into the seller wallet.',
|
|
527
|
+
},
|
|
528
|
+
],
|
|
529
|
+
propertyDefinitions,
|
|
530
|
+
functions,
|
|
531
|
+
...(automations.length ? { automations } : {}),
|
|
532
|
+
};
|
|
533
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type KitBlueprint } from './core.js';
|
|
2
|
+
/** Options for {@link guildBlueprint}. */
|
|
3
|
+
export interface GuildBlueprintOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Prefix for the composed type names (`'Guild'` → `GuildHall` /
|
|
6
|
+
* `GuildBankInventory`). Defaults to `'Guild'`.
|
|
7
|
+
*/
|
|
8
|
+
typePrefix?: string;
|
|
9
|
+
/**
|
|
10
|
+
* The guild team's group id — the hall's `group_permission` policy checks
|
|
11
|
+
* membership of THIS group. Create the team first
|
|
12
|
+
* (`kit.social.guild.create`), then deploy the blueprint. Deploy one
|
|
13
|
+
* prefixed blueprint per guild that needs its own hall.
|
|
14
|
+
*/
|
|
15
|
+
guildGroupId: string;
|
|
16
|
+
/**
|
|
17
|
+
* Optional group permission key the hall requires (e.g. a custom
|
|
18
|
+
* `use_hall` role permission). Omit to admit every guild member.
|
|
19
|
+
*/
|
|
20
|
+
hallPermission?: string;
|
|
21
|
+
/** Also compose a guild-bank inventory (`<prefix>Bank*`). Defaults to true. */
|
|
22
|
+
bank?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Names derived by {@link guildBlueprint} for a given prefix. */
|
|
25
|
+
export interface GuildNames {
|
|
26
|
+
hallType: string;
|
|
27
|
+
openHallFn: string;
|
|
28
|
+
closeHallFn: string;
|
|
29
|
+
bankTypePrefix: string;
|
|
30
|
+
bankInventoryType: string;
|
|
31
|
+
bankStackType: string;
|
|
32
|
+
}
|
|
33
|
+
/** Compute the type/function names a guild blueprint (and kit.social.guild) uses. */
|
|
34
|
+
export declare function guildNames(typePrefix?: string): GuildNames;
|
|
35
|
+
/**
|
|
36
|
+
* Composite blueprint for a **guild's shared assets** — a demonstration of
|
|
37
|
+
* blueprint composition: a `GuildHall` lockable whose open/close is gated on
|
|
38
|
+
* membership of the guild team (`group_permission`), plus a prefixed
|
|
39
|
+
* guild-bank inventory (`GuildBankInventory` / `GuildBankItemStack`) for
|
|
40
|
+
* shared storage. The guild itself is a **team** (`kit.social.guild`), its
|
|
41
|
+
* chat a **channel**, and its territory a grid group-grant
|
|
42
|
+
* (`kit.social.guild.claimTerritory`) — no new model surface needed for
|
|
43
|
+
* those.
|
|
44
|
+
*
|
|
45
|
+
* Runtime counterparts: `client.kit(appId).social.guild` (team/chat/territory),
|
|
46
|
+
* `kit.objectsFor(guildNames().hallType)` (the hall), and
|
|
47
|
+
* `client.kit(appId, { inventory: { typePrefix: guildNames().bankTypePrefix } })
|
|
48
|
+
* .inventory` (the bank).
|
|
49
|
+
*/
|
|
50
|
+
export declare function guildBlueprint(options: GuildBlueprintOptions): KitBlueprint;
|
|
51
|
+
//# sourceMappingURL=guild.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guild.d.ts","sourceRoot":"","sources":["../../../src/kit/blueprints/guild.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAIjE,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,kEAAkE;AAClE,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,UAAU,SAAU,GAAG,UAAU,CAW3D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,YAAY,CAoB3E"}
|