@crowdedkingdoms/crowdyjs 8.2.0 → 8.3.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 +21 -3
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +5 -1
- package/dist/index.d.ts +2 -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/package.json +1 -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,222 @@
|
|
|
1
|
+
import type { Scalars, SeedContainerInput, SeedContainerTypeInput, SeedEdgeInput, SeedFunctionInput, SeedGameModelInput, SeedPropertyDefInput, UpsertAutomationInput, UpsertAutomationTriggerInput } from '../../generated/graphql.js';
|
|
2
|
+
/**
|
|
3
|
+
* A composable invoke-policy rule tree, mirroring the server's authority
|
|
4
|
+
* rules (see the Game API "Game Models → Authority" guide). Serialized with
|
|
5
|
+
* {@link kitPolicyJson} into the `invokePolicyJson` a function carries.
|
|
6
|
+
*/
|
|
7
|
+
export type KitInvokePolicy = {
|
|
8
|
+
type: 'allow';
|
|
9
|
+
} | {
|
|
10
|
+
type: 'owner_of_self';
|
|
11
|
+
} | {
|
|
12
|
+
type: 'is_host';
|
|
13
|
+
} | {
|
|
14
|
+
type: 'is_current_turn';
|
|
15
|
+
} | {
|
|
16
|
+
type: 'is_participant';
|
|
17
|
+
} | {
|
|
18
|
+
type: 'is_automation';
|
|
19
|
+
} | {
|
|
20
|
+
type: 'tier_feature';
|
|
21
|
+
feature: string;
|
|
22
|
+
} | {
|
|
23
|
+
type: 'group_permission';
|
|
24
|
+
groupId: string;
|
|
25
|
+
permission?: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: 'grid_permission';
|
|
28
|
+
key: string;
|
|
29
|
+
gridId?: string;
|
|
30
|
+
} | {
|
|
31
|
+
type: 'condition';
|
|
32
|
+
expression: string;
|
|
33
|
+
} | {
|
|
34
|
+
type: 'and';
|
|
35
|
+
rules: KitInvokePolicy[];
|
|
36
|
+
} | {
|
|
37
|
+
type: 'or';
|
|
38
|
+
rules: KitInvokePolicy[];
|
|
39
|
+
} | {
|
|
40
|
+
type: 'not';
|
|
41
|
+
rule: KitInvokePolicy;
|
|
42
|
+
};
|
|
43
|
+
/** Serialize a {@link KitInvokePolicy} tree to the wire `invokePolicyJson`. */
|
|
44
|
+
export declare function kitPolicyJson(policy: KitInvokePolicy): string;
|
|
45
|
+
/**
|
|
46
|
+
* A grid-permission filter inside a selector: gates selves/candidates by
|
|
47
|
+
* whether the USER behind each container has/lacks an unexpired runtime grid
|
|
48
|
+
* permission. Requires a game-api with the permission-read selector support
|
|
49
|
+
* (v0.13.12+).
|
|
50
|
+
*/
|
|
51
|
+
export interface SelectorPermissionPredicate {
|
|
52
|
+
/** Where the container's user id comes from: its owner, or a property. */
|
|
53
|
+
userFrom: 'owner' | {
|
|
54
|
+
property: string;
|
|
55
|
+
};
|
|
56
|
+
op: 'has' | 'lacks';
|
|
57
|
+
/** Runtime permission key (e.g. 'access', 'update_voxel_data'). */
|
|
58
|
+
key: string;
|
|
59
|
+
/** Literal grid id, a property holding one, or omitted for "on ANY grid". */
|
|
60
|
+
grid?: number | string | {
|
|
61
|
+
property: string;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Typed automation selector (serialized into `selectorJson` at deploy).
|
|
66
|
+
* Property predicates (`selfWhere`/`where`) filter on model data; permission
|
|
67
|
+
* predicates (`selfPermissionWhere`/`candidatePermissionWhere`) filter on the
|
|
68
|
+
* live grid ACL. Extra fields pass through untouched.
|
|
69
|
+
*/
|
|
70
|
+
export interface KitSelectorSpec {
|
|
71
|
+
selfWhere?: Array<{
|
|
72
|
+
key: string;
|
|
73
|
+
op: string;
|
|
74
|
+
value: unknown;
|
|
75
|
+
}>;
|
|
76
|
+
selfPermissionWhere?: SelectorPermissionPredicate[];
|
|
77
|
+
pick?: 'nearest' | 'lowest' | 'highest' | 'random';
|
|
78
|
+
ofType?: string;
|
|
79
|
+
where?: Array<{
|
|
80
|
+
key: string;
|
|
81
|
+
op: string;
|
|
82
|
+
value: unknown;
|
|
83
|
+
}>;
|
|
84
|
+
candidatePermissionWhere?: SelectorPermissionPredicate[];
|
|
85
|
+
by?: 'manhattan' | {
|
|
86
|
+
property: string;
|
|
87
|
+
};
|
|
88
|
+
bindAs?: {
|
|
89
|
+
ref?: string;
|
|
90
|
+
x?: string;
|
|
91
|
+
y?: string;
|
|
92
|
+
approachX?: string;
|
|
93
|
+
approachY?: string;
|
|
94
|
+
approachStop?: number;
|
|
95
|
+
};
|
|
96
|
+
[key: string]: unknown;
|
|
97
|
+
}
|
|
98
|
+
/** An automation spec inside a blueprint (the `appId` is bound at deploy). */
|
|
99
|
+
export type KitAutomationSpec = Omit<UpsertAutomationInput, 'appId'>;
|
|
100
|
+
/** An automation event-trigger spec inside a blueprint. */
|
|
101
|
+
export type KitAutomationTriggerSpec = Omit<UpsertAutomationTriggerInput, 'appId'>;
|
|
102
|
+
/**
|
|
103
|
+
* A **blueprint**: a self-contained, declarative bundle of game-model
|
|
104
|
+
* definitions (container types, property defs, functions), optional seed
|
|
105
|
+
* instances, and optional automations that together implement one game
|
|
106
|
+
* concept (an inventory system, a lockable object, an NPC archetype).
|
|
107
|
+
*
|
|
108
|
+
* Blueprints are plain data — build them with {@link inventoryBlueprint},
|
|
109
|
+
* {@link lockBlueprint}, {@link npcBlueprint}, or by hand — then load them
|
|
110
|
+
* into an app with `client.kit(appId).deploy([...])` (requires the app-admin
|
|
111
|
+
* `manage_apps` permission). Deployment is idempotent: seeding upserts
|
|
112
|
+
* definitions and `upsertAutomation` keys on the automation name.
|
|
113
|
+
*/
|
|
114
|
+
export interface KitBlueprint {
|
|
115
|
+
/** A short identifier used in error messages (e.g. `'inventory'`). */
|
|
116
|
+
name: string;
|
|
117
|
+
containerTypes?: SeedContainerTypeInput[];
|
|
118
|
+
propertyDefinitions?: SeedPropertyDefInput[];
|
|
119
|
+
functions?: SeedFunctionInput[];
|
|
120
|
+
/** Optional shared/world containers to seed (catalog data, world objects). */
|
|
121
|
+
containers?: SeedContainerInput[];
|
|
122
|
+
/** Optional edges between seeded containers (by `tempId`). */
|
|
123
|
+
edges?: SeedEdgeInput[];
|
|
124
|
+
/** Server-driven automations to upsert after the seed. */
|
|
125
|
+
automations?: KitAutomationSpec[];
|
|
126
|
+
/** Event triggers to attach to the automations. */
|
|
127
|
+
automationTriggers?: KitAutomationTriggerSpec[];
|
|
128
|
+
}
|
|
129
|
+
/** Convert `PascalCase`/`camelCase` to `snake_case` for derived names. */
|
|
130
|
+
export declare function toSnakeCase(name: string): string;
|
|
131
|
+
/** The wire payloads {@link mergeBlueprints} produces for one deployment. */
|
|
132
|
+
export interface MergedBlueprints {
|
|
133
|
+
seedInput: SeedGameModelInput;
|
|
134
|
+
automations: UpsertAutomationInput[];
|
|
135
|
+
automationTriggers: UpsertAutomationTriggerInput[];
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Merge blueprints into a single `gameModelSeed` payload plus the automation
|
|
139
|
+
* upserts, rejecting duplicate type, property, function, or automation names
|
|
140
|
+
* across blueprints (a duplicate almost always means two blueprints need
|
|
141
|
+
* distinct prefixes/type names).
|
|
142
|
+
*/
|
|
143
|
+
export declare function mergeBlueprints(appId: Scalars['BigInt']['input'], blueprints: KitBlueprint[], options?: {
|
|
144
|
+
sessionId?: string;
|
|
145
|
+
}): MergedBlueprints;
|
|
146
|
+
/**
|
|
147
|
+
* Concatenate several blueprints into ONE composite blueprint (a plain
|
|
148
|
+
* client-side merge of the definition arrays — no collision checks; those
|
|
149
|
+
* happen in {@link mergeBlueprints} at deploy). Used by composite builders
|
|
150
|
+
* such as `guildBlueprint` that bundle other builders' output under a single
|
|
151
|
+
* name.
|
|
152
|
+
*/
|
|
153
|
+
export declare function composeBlueprints(name: string, blueprints: KitBlueprint[]): KitBlueprint;
|
|
154
|
+
/**
|
|
155
|
+
* Who may call a **trusted** mutation (XP grants, score submits, loot rolls,
|
|
156
|
+
* currency mints, …) — the kit-standard authority shape mirroring
|
|
157
|
+
* `LockAuthority` (Part of the anti-cheat conventions: reward-granting
|
|
158
|
+
* functions must never be plain player calls):
|
|
159
|
+
*
|
|
160
|
+
* - `'server'` — `invokeScope: "server"`: only app admins may invoke (run it
|
|
161
|
+
* from trusted studio/backend code holding `manage_apps`).
|
|
162
|
+
* - `'host'` — `is_host` policy: the elected host client may invoke.
|
|
163
|
+
* - `'automation'` — `autonomousInvocable` + `is_automation` policy: only
|
|
164
|
+
* server-driven automations may invoke.
|
|
165
|
+
* - `'owner'` — `owner_of_self`: the owning player (only safe for
|
|
166
|
+
* self-limiting functions guarded by conditions).
|
|
167
|
+
* - `{ custom: rule }` — any hand-written policy rule.
|
|
168
|
+
*/
|
|
169
|
+
export type KitTrustedAuthority = 'server' | 'host' | 'automation' | 'owner' | {
|
|
170
|
+
custom: KitInvokePolicy;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* The function-level fields a {@link KitTrustedAuthority} compiles to.
|
|
174
|
+
* `extraCondition` (when given) is AND'ed into the policy.
|
|
175
|
+
*/
|
|
176
|
+
export declare function trustedAuthorityFields(authority: KitTrustedAuthority, extraCondition?: string): Pick<{
|
|
177
|
+
invokePolicyJson: string;
|
|
178
|
+
invokeScope?: string;
|
|
179
|
+
autonomousInvocable?: boolean;
|
|
180
|
+
}, 'invokePolicyJson' | 'invokeScope' | 'autonomousInvocable'>;
|
|
181
|
+
/**
|
|
182
|
+
* AND extra policy rules into a base policy (skipping empties) — the
|
|
183
|
+
* composition point for `policyExtra` options such as
|
|
184
|
+
* `plotBlueprint({ buyPolicyExtra: featureGate('land_owner') })`.
|
|
185
|
+
*/
|
|
186
|
+
export declare function andPolicies(base: KitInvokePolicy, ...extra: Array<KitInvokePolicy | undefined>): KitInvokePolicy;
|
|
187
|
+
/**
|
|
188
|
+
* A `tier_feature` policy leaf: the caller's access tier must hold `feature`
|
|
189
|
+
* (defined via `kit.features.define` and granted with
|
|
190
|
+
* `kit.features.grantToTier`). Pass it to any builder's `*policyExtra`
|
|
191
|
+
* option to monetization-gate that function.
|
|
192
|
+
*/
|
|
193
|
+
export declare function featureGate(feature: string): KitInvokePolicy;
|
|
194
|
+
/**
|
|
195
|
+
* How kit types mirror their owner's user id into an `owner_user_id`
|
|
196
|
+
* property (expressions cannot read container ownership directly).
|
|
197
|
+
* The kit standard is `'int'`; set `'string'` on a builder only when
|
|
198
|
+
* integrating with models that mirrored the owner as a string (e.g. Blocks
|
|
199
|
+
* with Friends) — generated conditions then compare via `to_string(...)`.
|
|
200
|
+
*/
|
|
201
|
+
export type KitOwnerIdKind = 'int' | 'string';
|
|
202
|
+
/**
|
|
203
|
+
* Expression fragment asserting that `ownerExpr` (an `owner_user_id`-style
|
|
204
|
+
* property read) equals a user-id expression (usually the injected
|
|
205
|
+
* `$caller_user_id` / `$self_owner_id` system params), honoring
|
|
206
|
+
* {@link KitOwnerIdKind}.
|
|
207
|
+
*/
|
|
208
|
+
export declare function ownerEquals(ownerExpr: string, userExpr: string, kind?: KitOwnerIdKind): string;
|
|
209
|
+
/**
|
|
210
|
+
* Expression fragment asserting that `ownerExpr` (an `owner_user_id`-style
|
|
211
|
+
* property read) equals the calling user, honoring {@link KitOwnerIdKind}.
|
|
212
|
+
*/
|
|
213
|
+
export declare function ownerEqualsCaller(ownerExpr: string, kind?: KitOwnerIdKind): string;
|
|
214
|
+
/** The `SeedPropertyDefInput` for a kit-standard owner mirror property. */
|
|
215
|
+
export declare function ownerMirrorProperty(containerTypeName: string, kind?: KitOwnerIdKind): {
|
|
216
|
+
containerTypeName: string;
|
|
217
|
+
key: string;
|
|
218
|
+
valueType: string;
|
|
219
|
+
defaultValueJson: string;
|
|
220
|
+
description: string;
|
|
221
|
+
};
|
|
222
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/kit/blueprints/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/** Serialize a {@link KitInvokePolicy} tree to the wire `invokePolicyJson`. */
|
|
2
|
+
export function kitPolicyJson(policy) {
|
|
3
|
+
return JSON.stringify(policy);
|
|
4
|
+
}
|
|
5
|
+
/** Convert `PascalCase`/`camelCase` to `snake_case` for derived names. */
|
|
6
|
+
export function toSnakeCase(name) {
|
|
7
|
+
return name
|
|
8
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
9
|
+
.replace(/[\s-]+/g, '_')
|
|
10
|
+
.toLowerCase();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Merge blueprints into a single `gameModelSeed` payload plus the automation
|
|
14
|
+
* upserts, rejecting duplicate type, property, function, or automation names
|
|
15
|
+
* across blueprints (a duplicate almost always means two blueprints need
|
|
16
|
+
* distinct prefixes/type names).
|
|
17
|
+
*/
|
|
18
|
+
export function mergeBlueprints(appId, blueprints, options = {}) {
|
|
19
|
+
const containerTypes = [];
|
|
20
|
+
const propertyDefinitions = [];
|
|
21
|
+
const functions = [];
|
|
22
|
+
const containers = [];
|
|
23
|
+
const edges = [];
|
|
24
|
+
const automations = [];
|
|
25
|
+
const automationTriggers = [];
|
|
26
|
+
const seenTypes = new Map();
|
|
27
|
+
const seenProps = new Map();
|
|
28
|
+
const seenFunctions = new Map();
|
|
29
|
+
const seenAutomations = new Map();
|
|
30
|
+
const seenTempIds = new Map();
|
|
31
|
+
const claim = (seen, key, blueprintName, kind) => {
|
|
32
|
+
const existing = seen.get(key);
|
|
33
|
+
if (existing !== undefined) {
|
|
34
|
+
throw new Error(`Blueprint '${blueprintName}' redefines ${kind} '${key}' already defined by blueprint '${existing}'`);
|
|
35
|
+
}
|
|
36
|
+
seen.set(key, blueprintName);
|
|
37
|
+
};
|
|
38
|
+
for (const blueprint of blueprints) {
|
|
39
|
+
for (const type of blueprint.containerTypes ?? []) {
|
|
40
|
+
claim(seenTypes, type.typeName, blueprint.name, 'container type');
|
|
41
|
+
containerTypes.push(type);
|
|
42
|
+
}
|
|
43
|
+
for (const prop of blueprint.propertyDefinitions ?? []) {
|
|
44
|
+
claim(seenProps, `${prop.containerTypeName}.${prop.key}`, blueprint.name, 'property');
|
|
45
|
+
propertyDefinitions.push(prop);
|
|
46
|
+
}
|
|
47
|
+
for (const fn of blueprint.functions ?? []) {
|
|
48
|
+
claim(seenFunctions, fn.name, blueprint.name, 'function');
|
|
49
|
+
functions.push(fn);
|
|
50
|
+
}
|
|
51
|
+
for (const container of blueprint.containers ?? []) {
|
|
52
|
+
claim(seenTempIds, container.tempId, blueprint.name, 'container tempId');
|
|
53
|
+
containers.push(container);
|
|
54
|
+
}
|
|
55
|
+
edges.push(...(blueprint.edges ?? []));
|
|
56
|
+
for (const automation of blueprint.automations ?? []) {
|
|
57
|
+
claim(seenAutomations, automation.name, blueprint.name, 'automation');
|
|
58
|
+
automations.push({ ...automation, appId });
|
|
59
|
+
}
|
|
60
|
+
for (const trigger of blueprint.automationTriggers ?? []) {
|
|
61
|
+
automationTriggers.push({ ...trigger, appId });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const seedInput = {
|
|
65
|
+
appId,
|
|
66
|
+
...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
|
|
67
|
+
...(containerTypes.length ? { containerTypes } : {}),
|
|
68
|
+
...(propertyDefinitions.length ? { propertyDefinitions } : {}),
|
|
69
|
+
...(functions.length ? { functions } : {}),
|
|
70
|
+
...(containers.length ? { containers } : {}),
|
|
71
|
+
...(edges.length ? { edges } : {}),
|
|
72
|
+
};
|
|
73
|
+
return { seedInput, automations, automationTriggers };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Concatenate several blueprints into ONE composite blueprint (a plain
|
|
77
|
+
* client-side merge of the definition arrays — no collision checks; those
|
|
78
|
+
* happen in {@link mergeBlueprints} at deploy). Used by composite builders
|
|
79
|
+
* such as `guildBlueprint` that bundle other builders' output under a single
|
|
80
|
+
* name.
|
|
81
|
+
*/
|
|
82
|
+
export function composeBlueprints(name, blueprints) {
|
|
83
|
+
const out = { name };
|
|
84
|
+
for (const bp of blueprints) {
|
|
85
|
+
if (bp.containerTypes?.length) {
|
|
86
|
+
out.containerTypes = [...(out.containerTypes ?? []), ...bp.containerTypes];
|
|
87
|
+
}
|
|
88
|
+
if (bp.propertyDefinitions?.length) {
|
|
89
|
+
out.propertyDefinitions = [
|
|
90
|
+
...(out.propertyDefinitions ?? []),
|
|
91
|
+
...bp.propertyDefinitions,
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
if (bp.functions?.length) {
|
|
95
|
+
out.functions = [...(out.functions ?? []), ...bp.functions];
|
|
96
|
+
}
|
|
97
|
+
if (bp.containers?.length) {
|
|
98
|
+
out.containers = [...(out.containers ?? []), ...bp.containers];
|
|
99
|
+
}
|
|
100
|
+
if (bp.edges?.length) {
|
|
101
|
+
out.edges = [...(out.edges ?? []), ...bp.edges];
|
|
102
|
+
}
|
|
103
|
+
if (bp.automations?.length) {
|
|
104
|
+
out.automations = [...(out.automations ?? []), ...bp.automations];
|
|
105
|
+
}
|
|
106
|
+
if (bp.automationTriggers?.length) {
|
|
107
|
+
out.automationTriggers = [
|
|
108
|
+
...(out.automationTriggers ?? []),
|
|
109
|
+
...bp.automationTriggers,
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The function-level fields a {@link KitTrustedAuthority} compiles to.
|
|
117
|
+
* `extraCondition` (when given) is AND'ed into the policy.
|
|
118
|
+
*/
|
|
119
|
+
export function trustedAuthorityFields(authority, extraCondition) {
|
|
120
|
+
const rule = authority === 'server'
|
|
121
|
+
? { type: 'allow' }
|
|
122
|
+
: authority === 'host'
|
|
123
|
+
? { type: 'is_host' }
|
|
124
|
+
: authority === 'automation'
|
|
125
|
+
? { type: 'is_automation' }
|
|
126
|
+
: authority === 'owner'
|
|
127
|
+
? { type: 'owner_of_self' }
|
|
128
|
+
: authority.custom;
|
|
129
|
+
const policy = extraCondition
|
|
130
|
+
? { type: 'and', rules: [rule, { type: 'condition', expression: extraCondition }] }
|
|
131
|
+
: rule;
|
|
132
|
+
return {
|
|
133
|
+
invokePolicyJson: kitPolicyJson(policy),
|
|
134
|
+
...(authority === 'server' ? { invokeScope: 'server' } : {}),
|
|
135
|
+
...(authority === 'automation' ? { autonomousInvocable: true } : {}),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* AND extra policy rules into a base policy (skipping empties) — the
|
|
140
|
+
* composition point for `policyExtra` options such as
|
|
141
|
+
* `plotBlueprint({ buyPolicyExtra: featureGate('land_owner') })`.
|
|
142
|
+
*/
|
|
143
|
+
export function andPolicies(base, ...extra) {
|
|
144
|
+
const extras = extra.filter((r) => r !== undefined);
|
|
145
|
+
if (extras.length === 0)
|
|
146
|
+
return base;
|
|
147
|
+
return { type: 'and', rules: [base, ...extras] };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* A `tier_feature` policy leaf: the caller's access tier must hold `feature`
|
|
151
|
+
* (defined via `kit.features.define` and granted with
|
|
152
|
+
* `kit.features.grantToTier`). Pass it to any builder's `*policyExtra`
|
|
153
|
+
* option to monetization-gate that function.
|
|
154
|
+
*/
|
|
155
|
+
export function featureGate(feature) {
|
|
156
|
+
return { type: 'tier_feature', feature };
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Expression fragment asserting that `ownerExpr` (an `owner_user_id`-style
|
|
160
|
+
* property read) equals a user-id expression (usually the injected
|
|
161
|
+
* `$caller_user_id` / `$self_owner_id` system params), honoring
|
|
162
|
+
* {@link KitOwnerIdKind}.
|
|
163
|
+
*/
|
|
164
|
+
export function ownerEquals(ownerExpr, userExpr, kind = 'int') {
|
|
165
|
+
return kind === 'string'
|
|
166
|
+
? `${ownerExpr} == to_string(${userExpr})`
|
|
167
|
+
: `${ownerExpr} == ${userExpr}`;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Expression fragment asserting that `ownerExpr` (an `owner_user_id`-style
|
|
171
|
+
* property read) equals the calling user, honoring {@link KitOwnerIdKind}.
|
|
172
|
+
*/
|
|
173
|
+
export function ownerEqualsCaller(ownerExpr, kind = 'int') {
|
|
174
|
+
return ownerEquals(ownerExpr, '$caller_user_id', kind);
|
|
175
|
+
}
|
|
176
|
+
/** The `SeedPropertyDefInput` for a kit-standard owner mirror property. */
|
|
177
|
+
export function ownerMirrorProperty(containerTypeName, kind = 'int') {
|
|
178
|
+
return {
|
|
179
|
+
containerTypeName,
|
|
180
|
+
key: 'owner_user_id',
|
|
181
|
+
valueType: kind,
|
|
182
|
+
defaultValueJson: kind === 'string' ? '""' : '0',
|
|
183
|
+
description: "Mirror of the container owner's user id (kit convention: expressions cannot read container ownership).",
|
|
184
|
+
};
|
|
185
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type KitBlueprint, type KitOwnerIdKind } from './core.js';
|
|
2
|
+
/** Options for {@link decksBlueprint}. */
|
|
3
|
+
export interface DecksBlueprintOptions {
|
|
4
|
+
/** Prefix for the type/function names. Defaults to none. */
|
|
5
|
+
typePrefix?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Turn-based mode: adds `is_current_turn` to draw/play/discard, so only
|
|
8
|
+
* the player whose session turn it is may act. Defaults to false.
|
|
9
|
+
*/
|
|
10
|
+
turnBased?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Fan-out cap of the manual shuffle automation (raise it above your
|
|
13
|
+
* largest deck size). Defaults to 200.
|
|
14
|
+
*/
|
|
15
|
+
shuffleMaxTargets?: number;
|
|
16
|
+
/** Owner-mirror typing (see the kit convention). Defaults to `'int'`. */
|
|
17
|
+
ownerIdKind?: KitOwnerIdKind;
|
|
18
|
+
}
|
|
19
|
+
/** Names derived by {@link decksBlueprint} for a given prefix. */
|
|
20
|
+
export interface DecksNames {
|
|
21
|
+
cardDefType: string;
|
|
22
|
+
cardType: string;
|
|
23
|
+
drawFn: string;
|
|
24
|
+
playFn: string;
|
|
25
|
+
discardFn: string;
|
|
26
|
+
assignPositionFn: string;
|
|
27
|
+
shuffleAutomation: string;
|
|
28
|
+
}
|
|
29
|
+
/** Compute the type/function names a decks blueprint (and its runtime helper) uses. */
|
|
30
|
+
export declare function decksNames(typePrefix?: string): DecksNames;
|
|
31
|
+
/**
|
|
32
|
+
* Blueprint for **cards & hidden information**: an admin `CardDef` catalog
|
|
33
|
+
* and session-scoped `CardInstance`s whose `card_id` carries
|
|
34
|
+
* **`visibility: "owner"`** — the two-property hidden-info trick: only the
|
|
35
|
+
* owner's reads include `card_id`, while the public `revealed_card_id` stays
|
|
36
|
+
* empty until the card is played/discarded (the play function copies it in
|
|
37
|
+
* the same transaction). Opponents can see a card EXISTS in your hand, not
|
|
38
|
+
* what it is — enforced by read filtering, not client discipline.
|
|
39
|
+
*
|
|
40
|
+
* Shuffling is honest about the platform: expressions can't index arrays, so
|
|
41
|
+
* decks are ordered by a `position` int dealt by `assign_position`
|
|
42
|
+
* (`rand_int(0, 1000000)` per card) via a **manual, type-fan-out
|
|
43
|
+
* automation** — `kit.decks.shuffle()` runs it (admin), and drawing takes
|
|
44
|
+
* the owner's lowest-position deck card ("top of deck"; the runtime picks
|
|
45
|
+
* it, the server enforces the zone transition and ownership).
|
|
46
|
+
*
|
|
47
|
+
* Runtime counterpart: `client.kit(appId).decks`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function decksBlueprint(options?: DecksBlueprintOptions): KitBlueprint;
|
|
50
|
+
//# sourceMappingURL=decks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decks.d.ts","sourceRoot":"","sources":["../../../src/kit/blueprints/decks.ts"],"names":[],"mappings":"AAIA,OAAO,EAKL,KAAK,YAAY,EAEjB,KAAK,cAAc,EACpB,MAAM,WAAW,CAAC;AAEnB,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B;AAED,kEAAkE;AAClE,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,UAAU,SAAK,GAAG,UAAU,CAWtD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,YAAY,CAoJhF"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { kitPolicyJson, ownerMirrorProperty, toSnakeCase, } from './core.js';
|
|
2
|
+
/** Compute the type/function names a decks blueprint (and its runtime helper) uses. */
|
|
3
|
+
export function decksNames(typePrefix = '') {
|
|
4
|
+
const fnPrefix = typePrefix ? `${toSnakeCase(typePrefix)}_` : '';
|
|
5
|
+
return {
|
|
6
|
+
cardDefType: `${typePrefix}CardDef`,
|
|
7
|
+
cardType: `${typePrefix}CardInstance`,
|
|
8
|
+
drawFn: `${fnPrefix}draw_card`,
|
|
9
|
+
playFn: `${fnPrefix}play_card`,
|
|
10
|
+
discardFn: `${fnPrefix}discard_card`,
|
|
11
|
+
assignPositionFn: `${fnPrefix}assign_position`,
|
|
12
|
+
shuffleAutomation: `${fnPrefix.replace(/_/g, '-')}deck-shuffle`,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Blueprint for **cards & hidden information**: an admin `CardDef` catalog
|
|
17
|
+
* and session-scoped `CardInstance`s whose `card_id` carries
|
|
18
|
+
* **`visibility: "owner"`** — the two-property hidden-info trick: only the
|
|
19
|
+
* owner's reads include `card_id`, while the public `revealed_card_id` stays
|
|
20
|
+
* empty until the card is played/discarded (the play function copies it in
|
|
21
|
+
* the same transaction). Opponents can see a card EXISTS in your hand, not
|
|
22
|
+
* what it is — enforced by read filtering, not client discipline.
|
|
23
|
+
*
|
|
24
|
+
* Shuffling is honest about the platform: expressions can't index arrays, so
|
|
25
|
+
* decks are ordered by a `position` int dealt by `assign_position`
|
|
26
|
+
* (`rand_int(0, 1000000)` per card) via a **manual, type-fan-out
|
|
27
|
+
* automation** — `kit.decks.shuffle()` runs it (admin), and drawing takes
|
|
28
|
+
* the owner's lowest-position deck card ("top of deck"; the runtime picks
|
|
29
|
+
* it, the server enforces the zone transition and ownership).
|
|
30
|
+
*
|
|
31
|
+
* Runtime counterpart: `client.kit(appId).decks`.
|
|
32
|
+
*/
|
|
33
|
+
export function decksBlueprint(options = {}) {
|
|
34
|
+
const { typePrefix = '', turnBased = false, shuffleMaxTargets = 200, ownerIdKind: kind = 'int', } = options;
|
|
35
|
+
const names = decksNames(typePrefix);
|
|
36
|
+
const playerPolicy = (condition) => {
|
|
37
|
+
const rules = [
|
|
38
|
+
{ type: 'owner_of_self' },
|
|
39
|
+
...(turnBased ? [{ type: 'is_current_turn' }] : []),
|
|
40
|
+
{ type: 'condition', expression: condition },
|
|
41
|
+
];
|
|
42
|
+
return kitPolicyJson({ type: 'and', rules });
|
|
43
|
+
};
|
|
44
|
+
const propertyDefinitions = [
|
|
45
|
+
{
|
|
46
|
+
containerTypeName: names.cardDefType,
|
|
47
|
+
key: 'card_id',
|
|
48
|
+
valueType: 'string',
|
|
49
|
+
description: 'Stable card identifier (rules data lives on the def).',
|
|
50
|
+
},
|
|
51
|
+
ownerMirrorProperty(names.cardType, kind),
|
|
52
|
+
{
|
|
53
|
+
containerTypeName: names.cardType,
|
|
54
|
+
key: 'card_id',
|
|
55
|
+
valueType: 'string',
|
|
56
|
+
defaultValueJson: '""',
|
|
57
|
+
visibility: 'owner',
|
|
58
|
+
description: "WHICH card this is — owner-visible only (the hidden-information half of the two-property trick); opponents' reads omit it.",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
containerTypeName: names.cardType,
|
|
62
|
+
key: 'revealed_card_id',
|
|
63
|
+
valueType: 'string',
|
|
64
|
+
defaultValueJson: '""',
|
|
65
|
+
description: 'The public half: empty while the card hides in deck/hand, copied from card_id when played or discarded.',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
containerTypeName: names.cardType,
|
|
69
|
+
key: 'zone',
|
|
70
|
+
valueType: 'string',
|
|
71
|
+
defaultValueJson: '"deck"',
|
|
72
|
+
description: "Card zone: 'deck' | 'hand' | 'board' | 'discard'.",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
containerTypeName: names.cardType,
|
|
76
|
+
key: 'position',
|
|
77
|
+
valueType: 'int',
|
|
78
|
+
defaultValueJson: '0',
|
|
79
|
+
description: 'Deck order (lowest = top), dealt by the shuffle automation via rand_int.',
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
const functions = [
|
|
83
|
+
{
|
|
84
|
+
name: names.drawFn,
|
|
85
|
+
containerTypeName: names.cardType,
|
|
86
|
+
returnType: 'string',
|
|
87
|
+
mutations: [{ target: 'self', property: 'zone', expression: '"hand"' }],
|
|
88
|
+
returnExpression: 'self.zone',
|
|
89
|
+
invokePolicyJson: playerPolicy('self.zone == "deck"'),
|
|
90
|
+
description: 'Draw a card you own from your deck into your hand (the runtime picks the lowest-position deck card — "top of deck"); card_id stays owner-visible.',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: names.playFn,
|
|
94
|
+
containerTypeName: names.cardType,
|
|
95
|
+
returnType: 'string',
|
|
96
|
+
mutations: [
|
|
97
|
+
{ target: 'self', property: 'zone', expression: '"board"' },
|
|
98
|
+
{ target: 'self', property: 'revealed_card_id', expression: 'self.card_id' },
|
|
99
|
+
],
|
|
100
|
+
returnExpression: 'self.revealed_card_id',
|
|
101
|
+
invokePolicyJson: playerPolicy('self.zone == "hand"'),
|
|
102
|
+
description: 'Play a card from your hand: the zone flip AND the public reveal (revealed_card_id = card_id) commit together.',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: names.discardFn,
|
|
106
|
+
containerTypeName: names.cardType,
|
|
107
|
+
returnType: 'string',
|
|
108
|
+
mutations: [
|
|
109
|
+
{ target: 'self', property: 'zone', expression: '"discard"' },
|
|
110
|
+
{ target: 'self', property: 'revealed_card_id', expression: 'self.card_id' },
|
|
111
|
+
],
|
|
112
|
+
returnExpression: 'self.revealed_card_id',
|
|
113
|
+
invokePolicyJson: playerPolicy('self.zone == "hand" || self.zone == "board"'),
|
|
114
|
+
description: 'Discard a card face-up (discard piles are public information).',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: names.assignPositionFn,
|
|
118
|
+
containerTypeName: names.cardType,
|
|
119
|
+
returnType: 'int',
|
|
120
|
+
mutations: [
|
|
121
|
+
{ target: 'self', property: 'position', expression: 'rand_int(0, 1000000)' },
|
|
122
|
+
],
|
|
123
|
+
returnExpression: 'self.position',
|
|
124
|
+
invokePolicyJson: kitPolicyJson({ type: 'is_automation' }),
|
|
125
|
+
autonomousInvocable: true,
|
|
126
|
+
description: 'Shuffle step (automation-only): deals this card a random deck position — the supported server-side shuffle pattern (expressions cannot permute arrays).',
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
const automations = [
|
|
130
|
+
{
|
|
131
|
+
name: names.shuffleAutomation,
|
|
132
|
+
functionName: names.assignPositionFn,
|
|
133
|
+
targetMode: 'type',
|
|
134
|
+
targetTypeName: names.cardType,
|
|
135
|
+
triggerType: 'manual',
|
|
136
|
+
maxTargets: shuffleMaxTargets,
|
|
137
|
+
selectorJson: JSON.stringify({
|
|
138
|
+
selfWhere: [{ key: 'zone', op: '==', value: 'deck' }],
|
|
139
|
+
}),
|
|
140
|
+
description: 'Manual shuffle: fans assign_position out over every deck-zone card (run via gameModelRunAutomation / kit.decks.shuffle).',
|
|
141
|
+
},
|
|
142
|
+
];
|
|
143
|
+
return {
|
|
144
|
+
name: names.cardType,
|
|
145
|
+
containerTypes: [
|
|
146
|
+
{
|
|
147
|
+
typeName: names.cardDefType,
|
|
148
|
+
displayName: names.cardDefType,
|
|
149
|
+
instantiableBy: 'admin',
|
|
150
|
+
description: 'Studio card catalog row.',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
typeName: names.cardType,
|
|
154
|
+
displayName: names.cardType,
|
|
155
|
+
instantiableBy: 'member',
|
|
156
|
+
description: 'One card in play: hidden while in deck/hand (owner-visible card_id), public once revealed.',
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
propertyDefinitions,
|
|
160
|
+
functions,
|
|
161
|
+
automations,
|
|
162
|
+
};
|
|
163
|
+
}
|