@arken/node 1.5.0 → 1.5.2
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/build/modules/character/character.service.js.map +1 -1
- package/build/modules/chat/chat.service.js.map +1 -1
- package/build/modules/core/core.models.js.map +1 -1
- package/build/modules/core/core.service.js.map +1 -1
- package/build/modules/profile/profile.service.js.map +1 -1
- package/build/package.json +2 -2
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types.d.ts +1 -0
- package/build/types.js +1 -0
- package/build/types.js.map +1 -1
- package/build/util/mongo.js.map +1 -1
- package/db.ts +76 -1
- package/index.ts +351 -18
- package/{util/mongo.ts → mongo.ts} +2 -0
- package/package.json +3 -3
- package/tsconfig.json +33 -2
- package/types.ts +2 -0
- package/util.ts +1 -0
- package/modules/area/area.models.ts +0 -15
- package/modules/area/area.router.ts +0 -74
- package/modules/area/area.schema.ts +0 -22
- package/modules/area/area.service.ts +0 -124
- package/modules/area/area.types.ts +0 -26
- package/modules/area/index.ts +0 -5
- package/modules/asset/asset.models.ts +0 -59
- package/modules/asset/asset.router.ts +0 -55
- package/modules/asset/asset.schema.ts +0 -27
- package/modules/asset/asset.service.ts +0 -85
- package/modules/asset/asset.types.ts +0 -22
- package/modules/asset/index.ts +0 -5
- package/modules/chain/chain.models.ts +0 -50
- package/modules/chain/chain.router.ts +0 -104
- package/modules/chain/chain.schema.ts +0 -52
- package/modules/chain/chain.service.ts +0 -167
- package/modules/chain/chain.types.ts +0 -24
- package/modules/chain/index.ts +0 -5
- package/modules/character/character.models.ts +0 -174
- package/modules/character/character.router.ts +0 -314
- package/modules/character/character.schema.ts +0 -147
- package/modules/character/character.service.ts +0 -875
- package/modules/character/character.types.ts +0 -64
- package/modules/character/index.ts +0 -5
- package/modules/chat/chat.models.ts +0 -43
- package/modules/chat/chat.router.ts +0 -67
- package/modules/chat/chat.schema.ts +0 -36
- package/modules/chat/chat.service.ts +0 -120
- package/modules/chat/chat.types.ts +0 -20
- package/modules/chat/index.ts +0 -5
- package/modules/collection/collection.models.ts +0 -76
- package/modules/collection/collection.router.ts +0 -91
- package/modules/collection/collection.schema.ts +0 -90
- package/modules/collection/collection.service.ts +0 -192
- package/modules/collection/collection.types.ts +0 -36
- package/modules/collection/index.ts +0 -5
- package/modules/core/core.models.ts +0 -1379
- package/modules/core/core.router.ts +0 -1781
- package/modules/core/core.schema.ts +0 -847
- package/modules/core/core.service.ts +0 -2822
- package/modules/core/core.types.ts +0 -340
- package/modules/core/index.ts +0 -5
- package/modules/core/mail/applyPatchesOrMail.ts +0 -568
- package/modules/core/mail/mailClaimablePatchesBatch.ts +0 -381
- package/modules/game/game.models.ts +0 -53
- package/modules/game/game.router.ts +0 -110
- package/modules/game/game.schema.ts +0 -23
- package/modules/game/game.service.ts +0 -143
- package/modules/game/game.types.ts +0 -28
- package/modules/game/index.ts +0 -5
- package/modules/interface/index.ts +0 -5
- package/modules/interface/interface.canonicalize.ts +0 -279
- package/modules/interface/interface.models.ts +0 -40
- package/modules/interface/interface.router.ts +0 -175
- package/modules/interface/interface.schema.ts +0 -59
- package/modules/interface/interface.service.ts +0 -356
- package/modules/interface/interface.types.ts +0 -25
- package/modules/item/index.ts +0 -5
- package/modules/item/item.models.ts +0 -124
- package/modules/item/item.router.ts +0 -103
- package/modules/item/item.schema.ts +0 -120
- package/modules/item/item.service.ts +0 -167
- package/modules/item/item.types.ts +0 -74
- package/modules/job/index.ts +0 -5
- package/modules/job/job.models.ts +0 -14
- package/modules/job/job.router.ts +0 -44
- package/modules/job/job.schema.ts +0 -9
- package/modules/job/job.service.ts +0 -243
- package/modules/job/job.types.ts +0 -23
- package/modules/market/index.ts +0 -5
- package/modules/market/market.models.ts +0 -113
- package/modules/market/market.router.ts +0 -73
- package/modules/market/market.schema.ts +0 -140
- package/modules/market/market.service.ts +0 -122
- package/modules/market/market.types.ts +0 -56
- package/modules/product/index.ts +0 -5
- package/modules/product/product.models.ts +0 -166
- package/modules/product/product.router.ts +0 -93
- package/modules/product/product.schema.ts +0 -149
- package/modules/product/product.service.ts +0 -160
- package/modules/product/product.types.ts +0 -33
- package/modules/profile/index.ts +0 -5
- package/modules/profile/profile.models.ts +0 -214
- package/modules/profile/profile.router.ts +0 -72
- package/modules/profile/profile.schema.ts +0 -156
- package/modules/profile/profile.service.ts +0 -147
- package/modules/profile/profile.types.ts +0 -22
- package/modules/raffle/index.ts +0 -5
- package/modules/raffle/raffle.models.ts +0 -44
- package/modules/raffle/raffle.router.ts +0 -90
- package/modules/raffle/raffle.schema.ts +0 -32
- package/modules/raffle/raffle.service.ts +0 -167
- package/modules/raffle/raffle.types.ts +0 -30
- package/modules/skill/index.ts +0 -5
- package/modules/skill/skill.models.ts +0 -16
- package/modules/skill/skill.router.ts +0 -201
- package/modules/skill/skill.schema.ts +0 -40
- package/modules/skill/skill.service.ts +0 -390
- package/modules/skill/skill.types.ts +0 -33
- package/modules/video/index.ts +0 -5
- package/modules/video/video.models.ts +0 -25
- package/modules/video/video.router.ts +0 -143
- package/modules/video/video.schema.ts +0 -46
- package/modules/video/video.service.ts +0 -274
- package/modules/video/video.types.ts +0 -33
- package/util/db/index.ts +0 -7
- package/util/db/isPostgresError.ts +0 -9
- package/util/db/isUniqueConstraintViolation.ts +0 -3
- package/util/db.ts +0 -62
- package/util/index.ts +0 -351
- /package/{util/api.ts → api.ts} +0 -0
- /package/{util/array.ts → array.ts} +0 -0
- /package/{util/browser.ts → browser.ts} +0 -0
- /package/{util/codebase.ts → codebase.ts} +0 -0
- /package/{util/config.ts → config.ts} +0 -0
- /package/{util/decoder.test.ts → decoder.test.ts} +0 -0
- /package/{util/decoder.ts → decoder.ts} +0 -0
- /package/{util/format.ts → format.ts} +0 -0
- /package/{util/guid.ts → guid.ts} +0 -0
- /package/{util/json.ts → json.ts} +0 -0
- /package/{util/log.ts → log.ts} +0 -0
- /package/{util/math.ts → math.ts} +0 -0
- /package/{util/merkle.ts → merkle.ts} +0 -0
- /package/{util/number.ts → number.ts} +0 -0
- /package/{util/object.ts → object.ts} +0 -0
- /package/{util/otp.ts → otp.ts} +0 -0
- /package/{util/physics.ts → physics.ts} +0 -0
- /package/{util/process.ts → process.ts} +0 -0
- /package/{util/rpc.ts → rpc.ts} +0 -0
- /package/{util/seer.ts → seer.ts} +0 -0
- /package/{util/string.ts → string.ts} +0 -0
- /package/{util/text.ts → text.ts} +0 -0
- /package/{util/time → time}/date.ts +0 -0
- /package/{util/time → time}/fancyTimeFormat.ts +0 -0
- /package/{util/time → time}/index.ts +0 -0
- /package/{util/time → time}/now.ts +0 -0
- /package/{util/types → types}/mongo.d.ts +0 -0
- /package/{util/web3 → web3}/httpProvider.ts +0 -0
- /package/{util/web3.ts → web3.ts} +0 -0
- /package/{util/websocket.ts → websocket.ts} +0 -0
- /package/{util/zk.ts → zk.ts} +0 -0
- /package/{util/zod.ts → zod.ts} +0 -0
|
@@ -1,875 +0,0 @@
|
|
|
1
|
-
// arken/packages/node/modules/character/character.service.ts
|
|
2
|
-
//
|
|
3
|
-
import mongoose from 'mongoose';
|
|
4
|
-
import keccak256 from 'keccak256';
|
|
5
|
-
import type {
|
|
6
|
-
Character,
|
|
7
|
-
CharacterAbility,
|
|
8
|
-
CharacterAttribute,
|
|
9
|
-
CharacterClass,
|
|
10
|
-
CharacterFaction,
|
|
11
|
-
CharacterGender,
|
|
12
|
-
CharacterNameChoice,
|
|
13
|
-
CharacterPersonality,
|
|
14
|
-
CharacterRace,
|
|
15
|
-
CharacterTitle,
|
|
16
|
-
CharacterType,
|
|
17
|
-
Router,
|
|
18
|
-
RouterInput,
|
|
19
|
-
RouterOutput,
|
|
20
|
-
RouterContext,
|
|
21
|
-
} from './character.types';
|
|
22
|
-
import { ARXError } from '../../util/rpc';
|
|
23
|
-
import { getNextSeq, hashEvents } from '../../util/mongo';
|
|
24
|
-
import { updateLeafWithProof } from '../../util/merkle';
|
|
25
|
-
import { getFilter } from '../../util/api';
|
|
26
|
-
|
|
27
|
-
const TREE_DEPTH = 16;
|
|
28
|
-
const TREE_SIZE = 1 << TREE_DEPTH;
|
|
29
|
-
const LOCAL_SEER_ID = process.env.SEER_NODE_WALLET ?? 'seer-node-1';
|
|
30
|
-
|
|
31
|
-
// -------------------------------
|
|
32
|
-
// Inventory Sync Standard
|
|
33
|
-
// -------------------------------
|
|
34
|
-
export type InventorySyncOp =
|
|
35
|
-
| { op: 'add'; itemKey: string; quantity?: number }
|
|
36
|
-
| { op: 'remove'; itemKey: string; quantity?: number };
|
|
37
|
-
|
|
38
|
-
export type SyncCharacterInventoryPayload =
|
|
39
|
-
| {
|
|
40
|
-
characterId: string;
|
|
41
|
-
mode: 'patch';
|
|
42
|
-
ops: InventorySyncOp[];
|
|
43
|
-
reason?: string;
|
|
44
|
-
}
|
|
45
|
-
| {
|
|
46
|
-
characterId: string;
|
|
47
|
-
mode: 'refresh';
|
|
48
|
-
reason?: string;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// Deterministic mapping from (kind, recordId) -> Merkle leaf index
|
|
52
|
-
function computeLeafIndex(kind: string, recordId: string): number {
|
|
53
|
-
const h = keccak256(`${kind}:${recordId}`).toString('hex');
|
|
54
|
-
const first8 = h.slice(0, 8); // 32 bits
|
|
55
|
-
const n = parseInt(first8, 16);
|
|
56
|
-
return n % TREE_SIZE;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// -------------------------------
|
|
60
|
-
// Helpers
|
|
61
|
-
// -------------------------------
|
|
62
|
-
async function resolveCharacterForRequest(ctx: RouterContext, input: any) {
|
|
63
|
-
// const filter = getFilter(input);
|
|
64
|
-
const explicitId = input?.characterId;
|
|
65
|
-
// console.log('explicitId', input, filter, explicitId);
|
|
66
|
-
// Prefer explicit characterId if provided
|
|
67
|
-
// if (explicitId) {
|
|
68
|
-
const character = await ctx.app.model.Character.findById(explicitId);
|
|
69
|
-
if (!character) throw new Error('Character not found');
|
|
70
|
-
return character;
|
|
71
|
-
// }
|
|
72
|
-
|
|
73
|
-
// // Otherwise, fall back to "active" character = profile.characters[0]
|
|
74
|
-
// if (!ctx.client?.profile?.id) throw new Error('No profile');
|
|
75
|
-
// // @ts-ignore
|
|
76
|
-
// const character = await ctx.app.model.Character.findById(ctx.client.profile.characters?.[0].characterId);
|
|
77
|
-
// if (!character) throw new Error('No character');
|
|
78
|
-
|
|
79
|
-
// return character;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function ensureInventoryShape(character: any) {
|
|
83
|
-
if (!character.inventory) character.inventory = [{ items: [] }];
|
|
84
|
-
if (!character.inventory[0]) character.inventory[0] = { items: [] };
|
|
85
|
-
if (!Array.isArray(character.inventory[0].items)) character.inventory[0].items = [];
|
|
86
|
-
|
|
87
|
-
for (const item of character.inventory[0].items) {
|
|
88
|
-
console.log('item', item.itemId, item.itemId.valueOf());
|
|
89
|
-
item.itemId = item.itemId.valueOf();
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// -------------------------------
|
|
94
|
-
// Service
|
|
95
|
-
// -------------------------------
|
|
96
|
-
export class Service {
|
|
97
|
-
/**
|
|
98
|
-
* Sets the "active" character for the current profile.
|
|
99
|
-
*
|
|
100
|
-
* Convention used across codebase:
|
|
101
|
-
* - profile.characters[0] is treated as active character
|
|
102
|
-
*
|
|
103
|
-
* Implementation:
|
|
104
|
-
* - verify character exists and belongs to the caller
|
|
105
|
-
* - reorder profile.characters so the selected id is first
|
|
106
|
-
*/
|
|
107
|
-
/**
|
|
108
|
-
* Sets the active character for the current profile.
|
|
109
|
-
*
|
|
110
|
-
* Stores:
|
|
111
|
-
* profile.data.activeCharacterId = <characterId>
|
|
112
|
-
*
|
|
113
|
-
* Does NOT reorder profile.characters.
|
|
114
|
-
*/
|
|
115
|
-
async setActiveCharacter(input: { characterId: string }, ctx: RouterContext): Promise<{ characterId: string }> {
|
|
116
|
-
if (!ctx.client?.profile) throw new ARXError('UNAUTHORIZED');
|
|
117
|
-
if (!input?.characterId) throw new ARXError('NO_INPUT');
|
|
118
|
-
|
|
119
|
-
const profileId = ctx.client.profile.id;
|
|
120
|
-
const characterId = String(input.characterId);
|
|
121
|
-
|
|
122
|
-
// Ensure character exists
|
|
123
|
-
const character = await ctx.app.model.Character.findById(characterId).lean().exec();
|
|
124
|
-
if (!character) throw new Error('Character not found');
|
|
125
|
-
|
|
126
|
-
// Ensure ownership (saveCharacters sets ownerId = profile.id)
|
|
127
|
-
if (String((character as any).ownerId || '') !== String(profileId)) {
|
|
128
|
-
throw new ARXError('FORBIDDEN');
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Load profile and set pointer
|
|
132
|
-
const profile = await ctx.app.model.Profile.findById(profileId).exec();
|
|
133
|
-
if (!profile) throw new Error('Profile not found');
|
|
134
|
-
|
|
135
|
-
// ensure data shape
|
|
136
|
-
(profile as any).data =
|
|
137
|
-
(profile as any).data && typeof (profile as any).data === 'object' ? (profile as any).data : {};
|
|
138
|
-
(profile as any).data.activeCharacterId = characterId;
|
|
139
|
-
|
|
140
|
-
profile.markModified('data');
|
|
141
|
-
await profile.save();
|
|
142
|
-
|
|
143
|
-
ctx.client.profile.data = profile.data;
|
|
144
|
-
|
|
145
|
-
await ctx.client.emit.sync.mutate({
|
|
146
|
-
kind: 'invalidate',
|
|
147
|
-
targets: ['profile.me', 'trek.getState', 'character.inventory'],
|
|
148
|
-
reason: 'activeCharacterChanged',
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
return { characterId };
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Inventory: returns canonical inventory snapshot.
|
|
156
|
-
*
|
|
157
|
-
* This is the "full refresh" primitive; client can call this any time it needs to converge.
|
|
158
|
-
*
|
|
159
|
-
* NOTE: Uses the same filter semantics as other character routes:
|
|
160
|
-
* - if input includes characterId/id, we use that
|
|
161
|
-
* - otherwise we default to the user's first character
|
|
162
|
-
*/
|
|
163
|
-
async getCharacterInventory(
|
|
164
|
-
input: any, // intentionally loose so you can add RouterInput/Output wiring later
|
|
165
|
-
ctx: RouterContext
|
|
166
|
-
): Promise<{ characterId: string; inventory: any }> {
|
|
167
|
-
if (!ctx.client?.profile) throw new ARXError('UNAUTHORIZED');
|
|
168
|
-
|
|
169
|
-
const character = await resolveCharacterForRequest(ctx, input);
|
|
170
|
-
ensureInventoryShape(character);
|
|
171
|
-
|
|
172
|
-
return { characterId: character.id.toString(), inventory: character.inventory };
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Inventory: client convergence endpoint + "standard" payload.
|
|
177
|
-
*
|
|
178
|
-
* - mode=patch: client is telling us how it applied a local patch (add/remove)
|
|
179
|
-
* - mode=refresh: client requests canonical snapshot (recommended fallback)
|
|
180
|
-
*
|
|
181
|
-
* For now, this route simply returns the canonical snapshot so the client can converge.
|
|
182
|
-
* (Server-authoritative changes should still be persisted on the Character document by the
|
|
183
|
-
* gameplay systems, and then the UI can call this route or respond to emitted events.)
|
|
184
|
-
*/
|
|
185
|
-
async syncCharacterInventory(
|
|
186
|
-
input: SyncCharacterInventoryPayload,
|
|
187
|
-
ctx: RouterContext
|
|
188
|
-
): Promise<{ characterId: string; inventory: any }> {
|
|
189
|
-
if (!ctx.client?.profile) throw new ARXError('UNAUTHORIZED');
|
|
190
|
-
if (!input?.characterId) throw new ARXError('NO_INPUT');
|
|
191
|
-
|
|
192
|
-
const character = await ctx.app.model.Character.findById(input.characterId);
|
|
193
|
-
if (!character) throw new Error('Character not found');
|
|
194
|
-
|
|
195
|
-
ensureInventoryShape(character);
|
|
196
|
-
|
|
197
|
-
// Return canonical snapshot (client can always converge from this)
|
|
198
|
-
return { characterId: character.id.toString(), inventory: character.inventory };
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Optional server -> client push helper you can call from other services.
|
|
203
|
-
*
|
|
204
|
-
* Usage:
|
|
205
|
-
* await ctx.client.emit.syncCharacterInventory.mutate({ ...payload })
|
|
206
|
-
*/
|
|
207
|
-
async emitInventorySync(ctx: RouterContext, payload: SyncCharacterInventoryPayload) {
|
|
208
|
-
// You asked for this exact style: ctx.client.emit.SOMETHING.mutate(DATA_HERE)
|
|
209
|
-
try {
|
|
210
|
-
await (ctx.client as any)?.emit?.syncCharacterInventory?.mutate?.(payload);
|
|
211
|
-
} catch (e) {
|
|
212
|
-
// never crash gameplay because a websocket push failed
|
|
213
|
-
console.warn('Character.Service.emitInventorySync failed', e);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async exchangeCharacterItem(
|
|
218
|
-
input: RouterInput['exchangeCharacterItem'],
|
|
219
|
-
ctx: RouterContext
|
|
220
|
-
): Promise<RouterOutput['exchangeCharacterItem']> {
|
|
221
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
222
|
-
console.log('Character.Service.exchangeCharacterItem', input);
|
|
223
|
-
|
|
224
|
-
const filter = getFilter(input);
|
|
225
|
-
const character = await ctx.app.model.Character.findById(filter.characterId);
|
|
226
|
-
if (!character) throw new Error('Character not found');
|
|
227
|
-
|
|
228
|
-
// find the item on character
|
|
229
|
-
// see if the current player has the required item
|
|
230
|
-
// do the exchange
|
|
231
|
-
|
|
232
|
-
return character as Character;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
async getCharacterData(
|
|
236
|
-
input: RouterInput['getCharacter'],
|
|
237
|
-
ctx: RouterContext
|
|
238
|
-
): Promise<RouterOutput['getCharacter']> {
|
|
239
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
240
|
-
console.log('Character.Service.getCharacterData', input);
|
|
241
|
-
|
|
242
|
-
const filter = getFilter(input);
|
|
243
|
-
// @ts-ignore
|
|
244
|
-
const character = await ctx.app.model.Character.findOne(filter).asJSON();
|
|
245
|
-
if (!character) throw new Error('Character not found');
|
|
246
|
-
|
|
247
|
-
return character.data;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
async getCharacter(input: RouterInput['getCharacter'], ctx: RouterContext): Promise<RouterOutput['getCharacter']> {
|
|
251
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
252
|
-
console.log('Character.Service.getCharacter', input);
|
|
253
|
-
|
|
254
|
-
const filter = getFilter(input);
|
|
255
|
-
// @ts-ignore
|
|
256
|
-
const character = await ctx.app.model.Character.findOne(filter).asJSON();
|
|
257
|
-
if (!character) throw new Error('Character not found');
|
|
258
|
-
console.log('charactercharactercharacter', character);
|
|
259
|
-
return character as Character;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
async getCharacters(input: RouterInput['getCharacters'], ctx: RouterContext): Promise<RouterOutput['getCharacters']> {
|
|
263
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
264
|
-
|
|
265
|
-
const filter = getFilter(input);
|
|
266
|
-
|
|
267
|
-
const limit = input.limit ?? 50;
|
|
268
|
-
const skip = input.skip ?? 0;
|
|
269
|
-
|
|
270
|
-
const [items, total] = await Promise.all([
|
|
271
|
-
// @ts-ignore
|
|
272
|
-
ctx.app.model.Character.find(filter).skip(skip).limit(limit).asJSON(),
|
|
273
|
-
ctx.app.model.Character.find(filter).countDocuments().exec(),
|
|
274
|
-
]);
|
|
275
|
-
|
|
276
|
-
return { items, total };
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
async getCharacterAbility(
|
|
280
|
-
input: RouterInput['getCharacterAbility'],
|
|
281
|
-
ctx: RouterContext
|
|
282
|
-
): Promise<RouterOutput['getCharacterAbility']> {
|
|
283
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
284
|
-
console.log('Character.Service.getCharacterAbility', input);
|
|
285
|
-
|
|
286
|
-
const filter = getFilter(input);
|
|
287
|
-
const characterAbility = await ctx.app.model.CharacterAbility.findById(filter.id).lean().exec();
|
|
288
|
-
if (!characterAbility) throw new Error('CharacterAbility not found');
|
|
289
|
-
|
|
290
|
-
return characterAbility as CharacterAbility;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async saveCharacters(
|
|
294
|
-
input: RouterInput['saveCharacters'],
|
|
295
|
-
ctx: RouterContext
|
|
296
|
-
): Promise<RouterOutput['saveCharacters']> {
|
|
297
|
-
if (!input || !Array.isArray(input) || input.length === 0) {
|
|
298
|
-
throw new ARXError('NO_INPUT');
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const items: any[] = [];
|
|
302
|
-
const events: any[] = [];
|
|
303
|
-
const payloads: any[] = [];
|
|
304
|
-
|
|
305
|
-
for (const raw of input) {
|
|
306
|
-
// Allow id or _id; do not mutate original
|
|
307
|
-
const { id, _id, ...rest } = raw.data as any;
|
|
308
|
-
|
|
309
|
-
const previousId: string | mongoose.Types.ObjectId | undefined =
|
|
310
|
-
typeof id === 'string' || id instanceof mongoose.Types.ObjectId
|
|
311
|
-
? (id as any)
|
|
312
|
-
: _id instanceof mongoose.Types.ObjectId || typeof _id === 'string'
|
|
313
|
-
? (_id as any)
|
|
314
|
-
: undefined;
|
|
315
|
-
|
|
316
|
-
// Scope by applicationId if the Character model uses applicationId filters
|
|
317
|
-
if (ctx.app?.model?.Character?.filters?.applicationId && !rest.applicationId) {
|
|
318
|
-
rest.applicationId = ctx.app.model.Character.filters.applicationId;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if (!ctx.client.profile.id) {
|
|
322
|
-
throw new Error('No profile');
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
rest.ownerId = ctx.client.profile.id;
|
|
326
|
-
|
|
327
|
-
// Derive key from name if missing
|
|
328
|
-
if (!rest.key && typeof rest.name === 'string') {
|
|
329
|
-
rest.key = String(rest.name)
|
|
330
|
-
.trim()
|
|
331
|
-
.toLowerCase()
|
|
332
|
-
.replace(/[^a-z0-9\s-]/g, '')
|
|
333
|
-
.replace(/\s+/g, '-')
|
|
334
|
-
.replace(/-+/g, '-');
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// IMMUTABLE: always create a new Character document
|
|
338
|
-
const doc = await ctx.app.model.Character.create(rest);
|
|
339
|
-
const saved = doc?.toObject?.() ?? doc;
|
|
340
|
-
|
|
341
|
-
items.push(saved);
|
|
342
|
-
|
|
343
|
-
// Logical operation type (even though storage is immutable)
|
|
344
|
-
const op: 'create' | 'update' = previousId ? 'update' : 'create';
|
|
345
|
-
|
|
346
|
-
const event = {
|
|
347
|
-
kind: 'Character',
|
|
348
|
-
operation: op,
|
|
349
|
-
recordId: saved.id.toString(), // new doc id
|
|
350
|
-
applicationId: saved.applicationId,
|
|
351
|
-
payload: {
|
|
352
|
-
...saved,
|
|
353
|
-
previousId: previousId ? previousId.toString() : null,
|
|
354
|
-
},
|
|
355
|
-
timestamp: new Date(),
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
events.push(event);
|
|
359
|
-
|
|
360
|
-
// -----------------------------------------------------------------------
|
|
361
|
-
// Merkle + zkSNARK for this Character
|
|
362
|
-
// -----------------------------------------------------------------------
|
|
363
|
-
|
|
364
|
-
try {
|
|
365
|
-
const leafIndex = computeLeafIndex('Character', saved.id.toString());
|
|
366
|
-
|
|
367
|
-
// Poseidon-based Merkle update + zkSNARK proof using UpdateLeaf(16)
|
|
368
|
-
const merkleUpdate = await updateLeafWithProof(leafIndex, {
|
|
369
|
-
kind: 'Character',
|
|
370
|
-
id: saved.id.toString(),
|
|
371
|
-
status: saved.status,
|
|
372
|
-
key: saved.key,
|
|
373
|
-
applicationId: saved.applicationId,
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
// Build SeerPayload (one per character for now; you can batch later)
|
|
377
|
-
payloads.push({
|
|
378
|
-
fromSeer: LOCAL_SEER_ID,
|
|
379
|
-
applicationId: saved.applicationId,
|
|
380
|
-
events: [event],
|
|
381
|
-
eventsHash: hashEvents([event]),
|
|
382
|
-
merkleRoot: merkleUpdate.newRoot,
|
|
383
|
-
proof: merkleUpdate.proof,
|
|
384
|
-
publicSignals: merkleUpdate.publicSignals,
|
|
385
|
-
});
|
|
386
|
-
} catch (e) {
|
|
387
|
-
console.log('Merkle error when creating character');
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// -------------------------------------------------------------------------
|
|
392
|
-
// Persist SeerEvents with monotonic seq
|
|
393
|
-
// -------------------------------------------------------------------------
|
|
394
|
-
|
|
395
|
-
if (events.length > 0) {
|
|
396
|
-
const lastEvent = await ctx.app.model.SeerEvent.findOne().sort({ seq: -1 }).lean().exec();
|
|
397
|
-
const baseSeq = (lastEvent?.seq ?? 0) + 1;
|
|
398
|
-
|
|
399
|
-
const docsToInsert = events.map((ev, idx) => ({
|
|
400
|
-
...ev,
|
|
401
|
-
seq: baseSeq + idx,
|
|
402
|
-
}));
|
|
403
|
-
|
|
404
|
-
await ctx.app.model.SeerEvent.create(docsToInsert);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// -------------------------------------------------------------------------
|
|
408
|
-
// Persist SeerPayloads for cross-seer sync
|
|
409
|
-
// -------------------------------------------------------------------------
|
|
410
|
-
|
|
411
|
-
if (payloads.length > 0) {
|
|
412
|
-
await ctx.app.model.SeerPayload.create(payloads);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
const total = await ctx.app.model.Character.find().countDocuments().exec();
|
|
416
|
-
|
|
417
|
-
return { items, total };
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
async createCharacterAbility(
|
|
421
|
-
input: RouterInput['createCharacterAbility'],
|
|
422
|
-
ctx: RouterContext
|
|
423
|
-
): Promise<RouterOutput['createCharacterAbility']> {
|
|
424
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
425
|
-
console.log('Character.Service.createCharacterAbility', input);
|
|
426
|
-
|
|
427
|
-
const characterAbility = await ctx.app.model.CharacterAbility.create(input);
|
|
428
|
-
return characterAbility as CharacterAbility;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
async updateCharacter(
|
|
432
|
-
input: RouterInput['updateCharacter'],
|
|
433
|
-
ctx: RouterContext
|
|
434
|
-
): Promise<RouterOutput['updateCharacter']> {
|
|
435
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
436
|
-
console.log('Character.Service.updateCharacter', input);
|
|
437
|
-
|
|
438
|
-
const filter = getFilter(input);
|
|
439
|
-
const updatedCharacter = await ctx.app.model.Character.findByIdAndUpdate(filter.id, input.data, {
|
|
440
|
-
new: true,
|
|
441
|
-
})
|
|
442
|
-
.lean()
|
|
443
|
-
.exec();
|
|
444
|
-
if (!updatedCharacter) throw new Error('Character update failed');
|
|
445
|
-
|
|
446
|
-
return updatedCharacter as Character;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
async updateCharacterAbility(
|
|
450
|
-
input: RouterInput['updateCharacterAbility'],
|
|
451
|
-
ctx: RouterContext
|
|
452
|
-
): Promise<RouterOutput['updateCharacterAbility']> {
|
|
453
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
454
|
-
console.log('Character.Service.updateCharacterAbility', input);
|
|
455
|
-
|
|
456
|
-
const filter = getFilter(input);
|
|
457
|
-
const updatedCharacterAbility = await ctx.app.model.CharacterAbility.findByIdAndUpdate(filter.id, input.data, {
|
|
458
|
-
new: true,
|
|
459
|
-
})
|
|
460
|
-
.lean()
|
|
461
|
-
.exec();
|
|
462
|
-
if (!updatedCharacterAbility) throw new Error('CharacterAbility update failed');
|
|
463
|
-
|
|
464
|
-
return updatedCharacterAbility as CharacterAbility;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
async getCharacterAttribute(
|
|
468
|
-
input: RouterInput['getCharacterAttribute'],
|
|
469
|
-
ctx: RouterContext
|
|
470
|
-
): Promise<RouterOutput['getCharacterAttribute']> {
|
|
471
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
472
|
-
console.log('Character.Service.getCharacterAttribute', input);
|
|
473
|
-
|
|
474
|
-
const filter = getFilter(input);
|
|
475
|
-
const characterAttribute = await ctx.app.model.CharacterAttribute.findById(filter.id).lean().exec();
|
|
476
|
-
if (!characterAttribute) throw new Error('CharacterAttribute not found');
|
|
477
|
-
|
|
478
|
-
return characterAttribute as CharacterAttribute;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
async createCharacterAttribute(
|
|
482
|
-
input: RouterInput['createCharacterAttribute'],
|
|
483
|
-
ctx: RouterContext
|
|
484
|
-
): Promise<RouterOutput['createCharacterAttribute']> {
|
|
485
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
486
|
-
console.log('Character.Service.createCharacterAttribute', input);
|
|
487
|
-
|
|
488
|
-
const characterAttribute = await ctx.app.model.CharacterAttribute.create(input);
|
|
489
|
-
return characterAttribute as CharacterAttribute;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
async updateCharacterAttribute(
|
|
493
|
-
input: RouterInput['updateCharacterAttribute'],
|
|
494
|
-
ctx: RouterContext
|
|
495
|
-
): Promise<RouterOutput['updateCharacterAttribute']> {
|
|
496
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
497
|
-
console.log('Character.Service.updateCharacterAttribute', input);
|
|
498
|
-
|
|
499
|
-
const filter = getFilter(input);
|
|
500
|
-
const updatedCharacterAttribute = await ctx.app.model.CharacterAttribute.findByIdAndUpdate(filter.id, input.data, {
|
|
501
|
-
new: true,
|
|
502
|
-
})
|
|
503
|
-
.lean()
|
|
504
|
-
.exec();
|
|
505
|
-
if (!updatedCharacterAttribute) throw new Error('CharacterAttribute update failed');
|
|
506
|
-
|
|
507
|
-
return updatedCharacterAttribute as CharacterAttribute;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
async getCharacterClass(
|
|
511
|
-
input: RouterInput['getCharacterClass'],
|
|
512
|
-
ctx: RouterContext
|
|
513
|
-
): Promise<RouterOutput['getCharacterClass']> {
|
|
514
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
515
|
-
console.log('Character.Service.getCharacterClass', input);
|
|
516
|
-
|
|
517
|
-
const characterClass = await ctx.app.model.CharacterClass.findById(getFilter(input).id).lean().exec();
|
|
518
|
-
if (!characterClass) throw new Error('CharacterClass not found');
|
|
519
|
-
|
|
520
|
-
return characterClass as CharacterClass;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
async createCharacterClass(
|
|
524
|
-
input: RouterInput['createCharacterClass'],
|
|
525
|
-
ctx: RouterContext
|
|
526
|
-
): Promise<RouterOutput['createCharacterClass']> {
|
|
527
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
528
|
-
console.log('Character.Service.createCharacterClass', input);
|
|
529
|
-
|
|
530
|
-
const characterClass = await ctx.app.model.CharacterClass.create(input);
|
|
531
|
-
return characterClass as CharacterClass;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
async updateCharacterClass(
|
|
535
|
-
input: RouterInput['updateCharacterClass'],
|
|
536
|
-
ctx: RouterContext
|
|
537
|
-
): Promise<RouterOutput['updateCharacterClass']> {
|
|
538
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
539
|
-
console.log('Character.Service.updateCharacterClass', input);
|
|
540
|
-
|
|
541
|
-
const updatedCharacterClass = await ctx.app.model.CharacterClass.findByIdAndUpdate(
|
|
542
|
-
getFilter(input).id,
|
|
543
|
-
input.data,
|
|
544
|
-
{
|
|
545
|
-
new: true,
|
|
546
|
-
}
|
|
547
|
-
)
|
|
548
|
-
.lean()
|
|
549
|
-
.exec();
|
|
550
|
-
if (!updatedCharacterClass) throw new Error('CharacterClass update failed');
|
|
551
|
-
|
|
552
|
-
return updatedCharacterClass as CharacterClass;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
// Add similar methods for other character-related models...
|
|
556
|
-
|
|
557
|
-
async getCharacterFaction(
|
|
558
|
-
input: RouterInput['getCharacterFaction'],
|
|
559
|
-
ctx: RouterContext
|
|
560
|
-
): Promise<RouterOutput['getCharacterFaction']> {
|
|
561
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
562
|
-
console.log('Character.Service.getCharacterFaction', input);
|
|
563
|
-
|
|
564
|
-
const characterFaction = await ctx.app.model.CharacterFaction.findOne(getFilter(input)).lean().exec();
|
|
565
|
-
if (!characterFaction) throw new Error('CharacterFaction not found');
|
|
566
|
-
|
|
567
|
-
return characterFaction as CharacterFaction;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
async getCharacterFactions(
|
|
571
|
-
input: RouterInput['getCharacterFactions'],
|
|
572
|
-
ctx: RouterContext
|
|
573
|
-
): Promise<RouterOutput['getCharacterFactions']> {
|
|
574
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
575
|
-
console.log('Character.Service.getCharacterFactions', input);
|
|
576
|
-
|
|
577
|
-
const characterFactions = await ctx.app.model.CharacterFaction.find(getFilter(input)).lean().exec();
|
|
578
|
-
|
|
579
|
-
return characterFactions as CharacterFaction[];
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
async createCharacterFaction(
|
|
583
|
-
input: RouterInput['createCharacterFaction'],
|
|
584
|
-
ctx: RouterContext
|
|
585
|
-
): Promise<RouterOutput['createCharacterFaction']> {
|
|
586
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
587
|
-
console.log('Character.Service.createCharacterFaction', input);
|
|
588
|
-
|
|
589
|
-
const characterFaction = await ctx.app.model.CharacterFaction.create(input);
|
|
590
|
-
return characterFaction as CharacterFaction;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
async updateCharacterFaction(
|
|
594
|
-
input: RouterInput['updateCharacterFaction'],
|
|
595
|
-
ctx: RouterContext
|
|
596
|
-
): Promise<RouterOutput['updateCharacterFaction']> {
|
|
597
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
598
|
-
console.log('Character.Service.updateCharacterFaction', input);
|
|
599
|
-
|
|
600
|
-
const updatedCharacterFaction = await ctx.app.model.CharacterFaction.findByIdAndUpdate(
|
|
601
|
-
getFilter(input).id,
|
|
602
|
-
input.data,
|
|
603
|
-
{
|
|
604
|
-
new: true,
|
|
605
|
-
}
|
|
606
|
-
)
|
|
607
|
-
.lean()
|
|
608
|
-
.exec();
|
|
609
|
-
if (!updatedCharacterFaction) throw new Error('CharacterFaction update failed');
|
|
610
|
-
|
|
611
|
-
return updatedCharacterFaction as CharacterFaction;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
async getCharacterGender(
|
|
615
|
-
input: RouterInput['getCharacterGender'],
|
|
616
|
-
ctx: RouterContext
|
|
617
|
-
): Promise<RouterOutput['getCharacterGender']> {
|
|
618
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
619
|
-
console.log('Character.Service.getCharacterGender', input);
|
|
620
|
-
|
|
621
|
-
const characterGender = await ctx.app.model.CharacterGender.findById(getFilter(input).id).lean().exec();
|
|
622
|
-
if (!characterGender) throw new Error('CharacterGender not found');
|
|
623
|
-
|
|
624
|
-
return characterGender as CharacterGender;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
async createCharacterGender(
|
|
628
|
-
input: RouterInput['createCharacterGender'],
|
|
629
|
-
ctx: RouterContext
|
|
630
|
-
): Promise<RouterOutput['createCharacterGender']> {
|
|
631
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
632
|
-
console.log('Character.Service.createCharacterGender', input);
|
|
633
|
-
|
|
634
|
-
const characterGender = await ctx.app.model.CharacterGender.create(input);
|
|
635
|
-
return characterGender as CharacterGender;
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
async updateCharacterGender(
|
|
639
|
-
input: RouterInput['updateCharacterGender'],
|
|
640
|
-
ctx: RouterContext
|
|
641
|
-
): Promise<RouterOutput['updateCharacterGender']> {
|
|
642
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
643
|
-
console.log('Character.Service.updateCharacterGender', input);
|
|
644
|
-
|
|
645
|
-
const updatedCharacterGender = await ctx.app.model.CharacterGender.findByIdAndUpdate(
|
|
646
|
-
getFilter(input).id,
|
|
647
|
-
input.data,
|
|
648
|
-
{
|
|
649
|
-
new: true,
|
|
650
|
-
}
|
|
651
|
-
)
|
|
652
|
-
.lean()
|
|
653
|
-
.exec();
|
|
654
|
-
if (!updatedCharacterGender) throw new Error('CharacterGender update failed');
|
|
655
|
-
|
|
656
|
-
return updatedCharacterGender as CharacterGender;
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
async getCharacterNameChoice(
|
|
660
|
-
input: RouterInput['getCharacterNameChoice'],
|
|
661
|
-
ctx: RouterContext
|
|
662
|
-
): Promise<RouterOutput['getCharacterNameChoice']> {
|
|
663
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
664
|
-
console.log('Character.Service.getCharacterNameChoice', input);
|
|
665
|
-
|
|
666
|
-
const characterNameChoice = await ctx.app.model.CharacterNameChoice.findById(getFilter(input).id).lean().exec();
|
|
667
|
-
if (!characterNameChoice) throw new Error('CharacterNameChoice not found');
|
|
668
|
-
|
|
669
|
-
return characterNameChoice as CharacterNameChoice;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
async createCharacterNameChoice(
|
|
673
|
-
input: RouterInput['createCharacterNameChoice'],
|
|
674
|
-
ctx: RouterContext
|
|
675
|
-
): Promise<RouterOutput['createCharacterNameChoice']> {
|
|
676
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
677
|
-
console.log('Character.Service.createCharacterNameChoice', input);
|
|
678
|
-
|
|
679
|
-
const characterNameChoice = await ctx.app.model.CharacterNameChoice.create(input);
|
|
680
|
-
return characterNameChoice as CharacterNameChoice;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
async updateCharacterNameChoice(
|
|
684
|
-
input: RouterInput['updateCharacterNameChoice'],
|
|
685
|
-
ctx: RouterContext
|
|
686
|
-
): Promise<RouterOutput['updateCharacterNameChoice']> {
|
|
687
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
688
|
-
console.log('Character.Service.updateCharacterNameChoice', input);
|
|
689
|
-
|
|
690
|
-
const updatedCharacterNameChoice = await ctx.app.model.CharacterNameChoice.findByIdAndUpdate(
|
|
691
|
-
getFilter(input).id,
|
|
692
|
-
input.data,
|
|
693
|
-
{
|
|
694
|
-
new: true,
|
|
695
|
-
}
|
|
696
|
-
)
|
|
697
|
-
.lean()
|
|
698
|
-
.exec();
|
|
699
|
-
if (!updatedCharacterNameChoice) throw new Error('CharacterNameChoice update failed');
|
|
700
|
-
|
|
701
|
-
return updatedCharacterNameChoice as CharacterNameChoice;
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
async getCharacterPersonality(
|
|
705
|
-
input: RouterInput['getCharacterPersonality'],
|
|
706
|
-
ctx: RouterContext
|
|
707
|
-
): Promise<RouterOutput['getCharacterPersonality']> {
|
|
708
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
709
|
-
console.log('Character.Service.getCharacterPersonality', input);
|
|
710
|
-
|
|
711
|
-
const characterPersonality = await ctx.app.model.CharacterPersonality.findById(getFilter(input).id).lean().exec();
|
|
712
|
-
if (!characterPersonality) throw new Error('CharacterPersonality not found');
|
|
713
|
-
|
|
714
|
-
return characterPersonality as CharacterPersonality;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
async createCharacterPersonality(
|
|
718
|
-
input: RouterInput['createCharacterPersonality'],
|
|
719
|
-
ctx: RouterContext
|
|
720
|
-
): Promise<RouterOutput['createCharacterPersonality']> {
|
|
721
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
722
|
-
console.log('Character.Service.createCharacterPersonality', input);
|
|
723
|
-
|
|
724
|
-
const characterPersonality = await ctx.app.model.CharacterPersonality.create(input);
|
|
725
|
-
return characterPersonality as CharacterPersonality;
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
async updateCharacterPersonality(
|
|
729
|
-
input: RouterInput['updateCharacterPersonality'],
|
|
730
|
-
ctx: RouterContext
|
|
731
|
-
): Promise<RouterOutput['updateCharacterPersonality']> {
|
|
732
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
733
|
-
console.log('Character.Service.updateCharacterPersonality', input);
|
|
734
|
-
|
|
735
|
-
const updatedCharacterPersonality = await ctx.app.model.CharacterPersonality.findByIdAndUpdate(
|
|
736
|
-
getFilter(input).id,
|
|
737
|
-
input.data,
|
|
738
|
-
{
|
|
739
|
-
new: true,
|
|
740
|
-
}
|
|
741
|
-
)
|
|
742
|
-
.lean()
|
|
743
|
-
.exec();
|
|
744
|
-
if (!updatedCharacterPersonality) throw new Error('CharacterPersonality update failed');
|
|
745
|
-
|
|
746
|
-
return updatedCharacterPersonality as CharacterPersonality;
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
async getCharacterRace(
|
|
750
|
-
input: RouterInput['getCharacterRace'],
|
|
751
|
-
ctx: RouterContext
|
|
752
|
-
): Promise<RouterOutput['getCharacterRace']> {
|
|
753
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
754
|
-
console.log('Character.Service.getCharacterRace', input);
|
|
755
|
-
|
|
756
|
-
const characterRace = await ctx.app.model.CharacterRace.findById(getFilter(input).id).lean().exec();
|
|
757
|
-
if (!characterRace) throw new Error('CharacterRace not found');
|
|
758
|
-
|
|
759
|
-
return characterRace as CharacterRace;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
async createCharacterRace(
|
|
763
|
-
input: RouterInput['createCharacterRace'],
|
|
764
|
-
ctx: RouterContext
|
|
765
|
-
): Promise<RouterOutput['createCharacterRace']> {
|
|
766
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
767
|
-
console.log('Character.Service.createCharacterRace', input);
|
|
768
|
-
|
|
769
|
-
const characterRace = await ctx.app.model.CharacterRace.create(input);
|
|
770
|
-
return characterRace as CharacterRace;
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
async updateCharacterRace(
|
|
774
|
-
input: RouterInput['updateCharacterRace'],
|
|
775
|
-
ctx: RouterContext
|
|
776
|
-
): Promise<RouterOutput['updateCharacterRace']> {
|
|
777
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
778
|
-
console.log('Character.Service.updateCharacterRace', input);
|
|
779
|
-
|
|
780
|
-
const updatedCharacterRace = await ctx.app.model.CharacterRace.findByIdAndUpdate(getFilter(input).id, input.data, {
|
|
781
|
-
new: true,
|
|
782
|
-
})
|
|
783
|
-
.lean()
|
|
784
|
-
.exec();
|
|
785
|
-
if (!updatedCharacterRace) throw new Error('CharacterRace update failed');
|
|
786
|
-
|
|
787
|
-
return updatedCharacterRace as CharacterRace;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
async getCharacterTitle(
|
|
791
|
-
input: RouterInput['getCharacterTitle'],
|
|
792
|
-
ctx: RouterContext
|
|
793
|
-
): Promise<RouterOutput['getCharacterTitle']> {
|
|
794
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
795
|
-
console.log('Character.Service.getCharacterTitle', input);
|
|
796
|
-
|
|
797
|
-
const characterTitle = await ctx.app.model.CharacterTitle.findById(getFilter(input).id).lean().exec();
|
|
798
|
-
if (!characterTitle) throw new Error('CharacterTitle not found');
|
|
799
|
-
|
|
800
|
-
return characterTitle as CharacterTitle;
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
async createCharacterTitle(
|
|
804
|
-
input: RouterInput['createCharacterTitle'],
|
|
805
|
-
ctx: RouterContext
|
|
806
|
-
): Promise<RouterOutput['createCharacterTitle']> {
|
|
807
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
808
|
-
console.log('Character.Service.createCharacterTitle', input);
|
|
809
|
-
|
|
810
|
-
const characterTitle = await ctx.app.model.CharacterTitle.create(input);
|
|
811
|
-
return characterTitle as CharacterTitle;
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
async updateCharacterTitle(
|
|
815
|
-
input: RouterInput['updateCharacterTitle'],
|
|
816
|
-
ctx: RouterContext
|
|
817
|
-
): Promise<RouterOutput['updateCharacterTitle']> {
|
|
818
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
819
|
-
console.log('Character.Service.updateCharacterTitle', input);
|
|
820
|
-
|
|
821
|
-
const updatedCharacterTitle = await ctx.app.model.CharacterTitle.findByIdAndUpdate(
|
|
822
|
-
getFilter(input).id,
|
|
823
|
-
input.data,
|
|
824
|
-
{
|
|
825
|
-
new: true,
|
|
826
|
-
}
|
|
827
|
-
)
|
|
828
|
-
.lean()
|
|
829
|
-
.exec();
|
|
830
|
-
if (!updatedCharacterTitle) throw new Error('CharacterTitle update failed');
|
|
831
|
-
|
|
832
|
-
return updatedCharacterTitle as CharacterTitle;
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
async getCharacterType(
|
|
836
|
-
input: RouterInput['getCharacterType'],
|
|
837
|
-
ctx: RouterContext
|
|
838
|
-
): Promise<RouterOutput['getCharacterType']> {
|
|
839
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
840
|
-
console.log('Character.Service.getCharacterType', input);
|
|
841
|
-
|
|
842
|
-
const characterType = await ctx.app.model.CharacterType.findById(getFilter(input).id).lean().exec();
|
|
843
|
-
if (!characterType) throw new Error('CharacterType not found');
|
|
844
|
-
|
|
845
|
-
return characterType as CharacterType;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
async createCharacterType(
|
|
849
|
-
input: RouterInput['createCharacterType'],
|
|
850
|
-
ctx: RouterContext
|
|
851
|
-
): Promise<RouterOutput['createCharacterType']> {
|
|
852
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
853
|
-
console.log('Character.Service.createCharacterType', input);
|
|
854
|
-
|
|
855
|
-
const characterType = await ctx.app.model.CharacterType.create(input);
|
|
856
|
-
return characterType as CharacterType;
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
async updateCharacterType(
|
|
860
|
-
input: RouterInput['updateCharacterType'],
|
|
861
|
-
ctx: RouterContext
|
|
862
|
-
): Promise<RouterOutput['updateCharacterType']> {
|
|
863
|
-
if (!input) throw new ARXError('NO_INPUT');
|
|
864
|
-
console.log('Character.Service.updateCharacterType', input);
|
|
865
|
-
|
|
866
|
-
const updatedCharacterType = await ctx.app.model.CharacterType.findByIdAndUpdate(getFilter(input).id, input.data, {
|
|
867
|
-
new: true,
|
|
868
|
-
})
|
|
869
|
-
.lean()
|
|
870
|
-
.exec();
|
|
871
|
-
if (!updatedCharacterType) throw new Error('CharacterType update failed');
|
|
872
|
-
|
|
873
|
-
return updatedCharacterType as CharacterType;
|
|
874
|
-
}
|
|
875
|
-
}
|