@arken/seer-protocol 0.1.1 → 0.1.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.
Files changed (112) hide show
  1. package/.rush/temp/shrinkwrap-deps.json +537 -56
  2. package/area/area.models.ts +15 -0
  3. package/area/area.router.ts +74 -0
  4. package/area/area.schema.ts +22 -0
  5. package/area/area.types.ts +26 -0
  6. package/area/index.ts +5 -0
  7. package/asset/asset.models.ts +59 -0
  8. package/asset/asset.router.ts +55 -0
  9. package/asset/asset.schema.ts +27 -0
  10. package/asset/asset.types.ts +22 -0
  11. package/asset/index.ts +5 -0
  12. package/chain/chain.models.ts +50 -0
  13. package/chain/chain.router.ts +104 -0
  14. package/chain/chain.schema.ts +52 -0
  15. package/chain/chain.types.ts +24 -0
  16. package/chain/index.ts +5 -0
  17. package/character/character.models.ts +174 -0
  18. package/character/character.router.ts +314 -0
  19. package/character/character.schema.ts +147 -0
  20. package/character/character.types.ts +64 -0
  21. package/character/index.ts +5 -0
  22. package/chat/chat.models.ts +43 -0
  23. package/chat/chat.router.ts +67 -0
  24. package/chat/chat.schema.ts +36 -0
  25. package/chat/chat.types.ts +20 -0
  26. package/chat/index.ts +5 -0
  27. package/collection/collection.models.ts +76 -0
  28. package/collection/collection.router.ts +91 -0
  29. package/collection/collection.schema.ts +90 -0
  30. package/collection/collection.types.ts +36 -0
  31. package/collection/index.ts +5 -0
  32. package/core/core.models.ts +1380 -0
  33. package/core/core.router.ts +1781 -0
  34. package/core/core.schema.ts +847 -0
  35. package/core/core.types.ts +340 -0
  36. package/core/index.ts +5 -0
  37. package/evolution/evolution.models.ts +1 -1
  38. package/evolution/evolution.router.ts +8 -8
  39. package/evolution/evolution.schema.ts +1 -1
  40. package/evolution/evolution.types.ts +1 -1
  41. package/game/game.models.ts +53 -0
  42. package/game/game.router.ts +110 -0
  43. package/game/game.schema.ts +23 -0
  44. package/game/game.types.ts +28 -0
  45. package/game/index.ts +5 -0
  46. package/index.ts +39 -2
  47. package/infinite/infinite.models.ts +1 -1
  48. package/infinite/infinite.router.ts +8 -8
  49. package/infinite/infinite.schema.ts +1 -1
  50. package/infinite/infinite.types.ts +1 -1
  51. package/interface/index.ts +5 -0
  52. package/interface/interface.canonicalize.ts +279 -0
  53. package/interface/interface.models.ts +40 -0
  54. package/interface/interface.router.ts +175 -0
  55. package/interface/interface.schema.ts +59 -0
  56. package/interface/interface.types.ts +25 -0
  57. package/isles/isles.models.ts +1 -1
  58. package/isles/isles.router.ts +8 -8
  59. package/isles/isles.schema.ts +1 -1
  60. package/isles/isles.types.ts +1 -1
  61. package/item/index.ts +5 -0
  62. package/item/item.models.ts +124 -0
  63. package/item/item.router.ts +103 -0
  64. package/item/item.schema.ts +120 -0
  65. package/item/item.types.ts +74 -0
  66. package/job/index.ts +5 -0
  67. package/job/job.models.ts +14 -0
  68. package/job/job.router.ts +44 -0
  69. package/job/job.schema.ts +9 -0
  70. package/job/job.types.ts +23 -0
  71. package/market/index.ts +5 -0
  72. package/market/market.models.ts +113 -0
  73. package/market/market.router.ts +73 -0
  74. package/market/market.schema.ts +140 -0
  75. package/market/market.types.ts +56 -0
  76. package/oasis/oasis.models.ts +1 -1
  77. package/oasis/oasis.router.ts +2 -2
  78. package/oasis/oasis.schema.ts +1 -1
  79. package/oasis/oasis.types.ts +1 -1
  80. package/package.json +10 -3
  81. package/product/index.ts +5 -0
  82. package/product/product.models.ts +166 -0
  83. package/product/product.router.ts +93 -0
  84. package/product/product.schema.ts +149 -0
  85. package/product/product.types.ts +33 -0
  86. package/profile/index.ts +5 -0
  87. package/profile/profile.models.ts +214 -0
  88. package/profile/profile.router.ts +72 -0
  89. package/profile/profile.schema.ts +156 -0
  90. package/profile/profile.types.ts +22 -0
  91. package/raffle/index.ts +5 -0
  92. package/raffle/raffle.models.ts +44 -0
  93. package/raffle/raffle.router.ts +90 -0
  94. package/raffle/raffle.schema.ts +32 -0
  95. package/raffle/raffle.types.ts +30 -0
  96. package/router.ts +23 -29
  97. package/schema.ts +321 -0
  98. package/skill/index.ts +5 -0
  99. package/skill/skill.models.ts +16 -0
  100. package/skill/skill.router.ts +201 -0
  101. package/skill/skill.schema.ts +40 -0
  102. package/skill/skill.types.ts +33 -0
  103. package/trek/trek.models.ts +1 -1
  104. package/trek/trek.router.ts +1 -1
  105. package/trek/trek.schema.ts +1 -1
  106. package/trek/trek.types.ts +1 -1
  107. package/types.ts +172 -5
  108. package/video/index.ts +5 -0
  109. package/video/video.models.ts +25 -0
  110. package/video/video.router.ts +143 -0
  111. package/video/video.schema.ts +46 -0
  112. package/video/video.types.ts +33 -0
@@ -0,0 +1,1380 @@
1
+ // node/modules/core/core.models.ts
2
+
3
+ import * as mongo from '../../util/mongo';
4
+ import type * as Types from './core.types';
5
+
6
+ const { createModel, addTagVirtuals, addApplicationVirtual } = mongo;
7
+
8
+ // MerkleTree Model
9
+ export const MerkleTree = createModel<Types.MerkleTreeDocument>(
10
+ 'MerkleTree',
11
+ {
12
+ root: { type: String, required: true, default: '0x' + '0'.repeat(64) },
13
+ depth: { type: Number, required: true, default: 16 }, // log2(#leaves)
14
+ },
15
+ {
16
+ // extend: 'CommonFields',
17
+ virtuals: [...addTagVirtuals('MerkleTree'), ...addApplicationVirtual()],
18
+ }
19
+ );
20
+
21
+ // MerkleNode Model
22
+ export const MerkleNode = createModel<Types.MerkleNodeDocument>(
23
+ 'MerkleNode',
24
+ {
25
+ treeId: { type: mongo.Schema.Types.ObjectId, ref: 'MerkleTree', required: true },
26
+ level: { type: Number, required: true }, // 0 = leaves
27
+ index: { type: Number, required: true }, // position in level
28
+ hash: { type: String, required: true },
29
+ },
30
+ {
31
+ // extend: 'CommonFields',
32
+ indexes: [{ treeId: 1, level: 1, index: 1 }],
33
+ virtuals: [...addTagVirtuals('MerkleNode'), ...addApplicationVirtual()],
34
+ }
35
+ );
36
+
37
+ // Omniverse Model
38
+ export const Omniverse = createModel<Types.OmniverseDocument>(
39
+ 'Omniverse',
40
+ {
41
+ ratingId: { type: mongo.Schema.Types.ObjectId, ref: 'Rating' },
42
+ },
43
+ {
44
+ extend: 'CommonFields',
45
+ virtuals: [...addTagVirtuals('Omniverse'), ...addApplicationVirtual()],
46
+ }
47
+ );
48
+
49
+ // Metaverse Model
50
+ export const Metaverse = createModel<Types.MetaverseDocument>(
51
+ 'Metaverse',
52
+ {
53
+ omniverseId: { type: mongo.Schema.Types.ObjectId, ref: 'Omniverse', required: true },
54
+ ratingId: { type: mongo.Schema.Types.ObjectId, ref: 'Rating' },
55
+ },
56
+ {
57
+ extend: 'CommonFields',
58
+ virtuals: [...addTagVirtuals('Metaverse'), ...addApplicationVirtual()],
59
+ }
60
+ );
61
+
62
+ // Application Model
63
+ export const Application = createModel<Types.ApplicationDocument>(
64
+ 'Application',
65
+ {
66
+ ownerId: { type: mongo.Schema.Types.ObjectId, ref: 'Account' },
67
+ metaverseId: { type: mongo.Schema.Types.ObjectId, ref: 'Metaverse' },
68
+ name: { type: String, required: true },
69
+ description: { type: String },
70
+ },
71
+ {
72
+ extend: 'CommonFields',
73
+ indexes: [{ metaverseId: 1, name: 1, unique: true }],
74
+ virtuals: [
75
+ ...addTagVirtuals('Application'),
76
+ { name: 'agents', ref: 'Agent', localField: '_id', foreignField: 'applicationId' },
77
+ { name: 'chain' },
78
+ { name: 'account' },
79
+ { name: 'assets' },
80
+ { name: 'badges' },
81
+ { name: 'battlePasses' },
82
+ { name: 'collections' },
83
+ { name: 'communities' },
84
+ { name: 'discussions' },
85
+ { name: 'events' },
86
+ { name: 'exchanges' },
87
+ { name: 'files' },
88
+ { name: 'ideas' },
89
+ { name: 'leaderboards' },
90
+ { name: 'assetLicenses' },
91
+ { name: 'logs' },
92
+ { name: 'marketPairs' },
93
+ { name: 'markets' },
94
+ { name: 'messages' },
95
+ { name: 'offers' },
96
+ { name: 'orders' },
97
+ { name: 'products' },
98
+ { name: 'projects' },
99
+ { name: 'ratings' },
100
+ { name: 'realms' },
101
+ { name: 'reviews' },
102
+ { name: 'roles' },
103
+ { name: 'realmShards' },
104
+ { name: 'suggestions' },
105
+ { name: 'tags' },
106
+ { name: 'tokens' },
107
+ { name: 'tradeIdeas' },
108
+ { name: 'trades' },
109
+ { name: 'buyerTrades' },
110
+ { name: 'transactions' },
111
+ { name: 'votes' },
112
+ { name: 'payments' },
113
+ { name: 'permissions' },
114
+ { name: 'stats' },
115
+ { name: 'revisions' },
116
+ { name: 'comments' },
117
+ { name: 'interfaces' },
118
+ { name: 'characters' },
119
+ { name: 'metaverses' },
120
+ { name: 'omniverses' },
121
+ { name: 'referrals' },
122
+ { name: 'recipientReferrals' },
123
+ { name: 'senderReferrals' },
124
+ { name: 'chains' },
125
+ { name: 'characterAbilities' },
126
+ { name: 'tournaments' },
127
+ { name: 'teams' },
128
+ { name: 'items' },
129
+ { name: 'skills' },
130
+ { name: 'itemRecipes' },
131
+ { name: 'itemSkins' },
132
+ { name: 'stashes' },
133
+ { name: 'biomes' },
134
+ { name: 'planets' },
135
+ { name: 'solarSystems' },
136
+ { name: 'universes' },
137
+ { name: 'stars' },
138
+ { name: 'areas' },
139
+ { name: 'acts' },
140
+ { name: 'characterClasses' },
141
+ { name: 'characterFactions' },
142
+ { name: 'eras' },
143
+ { name: 'seasons' },
144
+ { name: 'itemAttributes' },
145
+ { name: 'itemMaterials' },
146
+ { name: 'itemSets' },
147
+ { name: 'itemSlots' },
148
+ { name: 'itemRarities' },
149
+ { name: 'itemTypes' },
150
+ { name: 'itemSubTypes' },
151
+ { name: 'itemSpecificTypes' },
152
+ { name: 'characterGenders' },
153
+ { name: 'characterRaces' },
154
+ { name: 'characterPersonalities' },
155
+ { name: 'characterTitles' },
156
+ { name: 'lores' },
157
+ { name: 'energies' },
158
+ { name: 'guides' },
159
+ { name: 'achievements' },
160
+ { name: 'games' },
161
+ { name: 'npcs' },
162
+ { name: 'characterAttributes' },
163
+ { name: 'characterTypes' },
164
+ { name: 'areaTypes' },
165
+ { name: 'areaLandmarks' },
166
+ { name: 'biomeFeatures' },
167
+ { name: 'skillMods' },
168
+ { name: 'skillClassifications' },
169
+ { name: 'skillConditions' },
170
+ { name: 'skillStatusEffects' },
171
+ { name: 'skillTrees' },
172
+ { name: 'skillTreeNodes' },
173
+ { name: 'areaNameChoices' },
174
+ { name: 'characterNameChoices' },
175
+ { name: 'validators' },
176
+ { name: 'productUpdates' },
177
+ { name: 'polls' },
178
+ { name: 'galaxies' },
179
+ { name: 'quests' },
180
+ { name: 'raffles' },
181
+ { name: 'raffleEntries' },
182
+ { name: 'raffleRequirements' },
183
+ { name: 'raffleRewards' },
184
+ { name: 'proposals' },
185
+ { name: 'companies' },
186
+ { name: 'people' },
187
+ ],
188
+ }
189
+ );
190
+
191
+ // Account Model
192
+ export const Account = createModel<Types.AccountDocument>(
193
+ 'Account',
194
+ {
195
+ username: { type: String },
196
+ email: { type: String },
197
+ address: { type: String },
198
+ addressIndex: { type: Number },
199
+ telegramUserId: { type: Number },
200
+ activeProfileId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile' },
201
+ sessionUserId: { type: String },
202
+ },
203
+ {
204
+ indexes: [
205
+ // { applicationId: 1, username: 1, unique: true },
206
+ {
207
+ fields: { applicationId: 1, telegramUserId: 1 },
208
+ options: {
209
+ unique: true,
210
+ partialFilterExpression: { telegramUserId: { $exists: true } },
211
+ },
212
+ },
213
+ ],
214
+ virtuals: [
215
+ {
216
+ name: 'profiles',
217
+ ref: 'Profile',
218
+ localField: '_id',
219
+ foreignField: 'accountId',
220
+ justOne: false,
221
+ },
222
+ ...addTagVirtuals('Account'),
223
+ ...addApplicationVirtual(),
224
+ ],
225
+ }
226
+ );
227
+
228
+ // Achievement Model
229
+ export const Achievement = createModel<Types.AchievementDocument>(
230
+ 'Achievement',
231
+ {},
232
+ {
233
+ virtuals: [...addTagVirtuals('Achievement'), ...addApplicationVirtual()],
234
+ }
235
+ );
236
+
237
+ // Act Model
238
+ export const Act = createModel<Types.ActDocument>(
239
+ 'Act',
240
+ {},
241
+ {
242
+ virtuals: [...addTagVirtuals('Act'), ...addApplicationVirtual()],
243
+ }
244
+ );
245
+
246
+ // Agent Model
247
+ export const Agent = createModel<Types.AgentDocument>(
248
+ 'Agent',
249
+ {},
250
+ {
251
+ virtuals: [...addTagVirtuals('Agent'), ...addApplicationVirtual()],
252
+ }
253
+ );
254
+
255
+ // Badge Model
256
+ export const Badge = createModel<Types.BadgeDocument>(
257
+ 'Badge',
258
+ {},
259
+ {
260
+ virtuals: [...addTagVirtuals('Badge'), ...addApplicationVirtual()],
261
+ }
262
+ );
263
+
264
+ // BattlePass Model
265
+ export const BattlePass = createModel<Types.BattlePassDocument>(
266
+ 'BattlePass',
267
+ {},
268
+ {
269
+ virtuals: [...addTagVirtuals('BattlePass'), ...addApplicationVirtual()],
270
+ }
271
+ );
272
+
273
+ // Biome Model
274
+ export const Biome = createModel<Types.BiomeDocument>(
275
+ 'Biome',
276
+ {},
277
+ {
278
+ virtuals: [...addTagVirtuals('Biome'), ...addApplicationVirtual()],
279
+ }
280
+ );
281
+
282
+ // BiomeFeature Model
283
+ export const BiomeFeature = createModel<Types.BiomeFeatureDocument>(
284
+ 'BiomeFeature',
285
+ {},
286
+ {
287
+ virtuals: [...addTagVirtuals('BiomeFeature'), ...addApplicationVirtual()],
288
+ }
289
+ );
290
+
291
+ // Bounty Model
292
+ export const Bounty = createModel<Types.BountyDocument>(
293
+ 'Bounty',
294
+ {},
295
+ {
296
+ virtuals: [...addTagVirtuals('Bounty'), ...addApplicationVirtual()],
297
+ }
298
+ );
299
+
300
+ export const Counter = createModel<Types.CounterDocument>(
301
+ 'Counter',
302
+ // @ts-ignore
303
+ { _id: { type: String, required: true }, seq: { type: Number, default: 0 } },
304
+ { versionKey: false, virtuals: [...addTagVirtuals('Counter'), ...addApplicationVirtual()] }
305
+ );
306
+
307
+ // Collection Model
308
+ export const Collection = createModel<Types.CollectionDocument>(
309
+ 'Collection',
310
+ {},
311
+ {
312
+ virtuals: [...addTagVirtuals('Collection'), ...addApplicationVirtual()],
313
+ }
314
+ );
315
+
316
+ // Comment Model
317
+ export const Comment = createModel<Types.CommentDocument>(
318
+ 'Comment',
319
+ {
320
+ body: { type: String, required: true },
321
+ entity: { type: mongo.Schema.Types.ObjectId },
322
+ entityModel: { type: String },
323
+ text: { type: String },
324
+ ratingId: { type: mongo.Schema.Types.ObjectId, ref: 'Rating' },
325
+ },
326
+ {
327
+ virtuals: [...addTagVirtuals('Comment'), ...addApplicationVirtual()],
328
+ }
329
+ );
330
+
331
+ // Community Model
332
+ export const Community = createModel<Types.CommunityDocument>(
333
+ 'Community',
334
+ {
335
+ ideas: [{ type: mongo.Schema.Types.ObjectId, ref: 'Idea' }],
336
+ products: [{ type: mongo.Schema.Types.ObjectId, ref: 'Product' }],
337
+ projects: [{ type: mongo.Schema.Types.ObjectId, ref: 'Project' }],
338
+ },
339
+ {
340
+ virtuals: [...addTagVirtuals('Community'), ...addApplicationVirtual()],
341
+ }
342
+ );
343
+
344
+ // Company Model
345
+ export const Company = createModel<Types.CompanyDocument>(
346
+ 'Company',
347
+ {
348
+ content: { type: String },
349
+ people: [{ type: mongo.Schema.Types.ObjectId, ref: 'Person' }],
350
+ },
351
+ {
352
+ virtuals: [...addTagVirtuals('Company'), ...addApplicationVirtual()],
353
+ }
354
+ );
355
+
356
+ // =========================
357
+ // Conversation (Thread)
358
+ // =========================
359
+ //
360
+ // Key points:
361
+ // - "mailboxKey" gives you a stable unique identity for system inbox threads.
362
+ // - Participants field-level index removed; indexes centralized below.
363
+ // - lastMessageDate naming normalized.
364
+ // - Back-compat messages[] kept, but consider disabling pushes or capping.
365
+ //
366
+ export const Conversation = createModel<Types.ConversationDocument>(
367
+ 'Conversation',
368
+ {
369
+ // Back-compat: old "owner" thread (mailbox-style threads should set this)
370
+ profileId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile', index: true },
371
+
372
+ // Mail/chat type
373
+ kind: {
374
+ type: String,
375
+ enum: ['mail', 'dm', 'group', 'support', 'system'],
376
+ default: 'mail',
377
+ index: true,
378
+ },
379
+
380
+ // Participants so the same model can do mail+discord-like threads
381
+ participants: [
382
+ {
383
+ profileId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile', required: true },
384
+
385
+ role: { type: String, enum: ['user', 'system', 'gm', 'npc'], default: 'user' },
386
+
387
+ lastReadAt: { type: Date, default: new Date(0) },
388
+ unreadCount: { type: Number, default: 0 },
389
+
390
+ isMuted: { type: Boolean, default: false },
391
+ isPinned: { type: Boolean, default: false },
392
+ isArchived: { type: Boolean, default: false },
393
+ isDeleted: { type: Boolean, default: false },
394
+ },
395
+ ],
396
+
397
+ isLocked: { type: Boolean, default: true },
398
+ allowUserSend: { type: Boolean, default: false },
399
+
400
+ category: { type: String, default: 'system' },
401
+ importance: { type: Number, default: 0 },
402
+
403
+ // ✅ keep consistent with your service code (use lastMessageDate everywhere)
404
+ lastMessageDate: { type: Date, default: null, index: true },
405
+ lastMessagePreview: { type: String, default: '' },
406
+ messageCount: { type: Number, default: 0 },
407
+
408
+ // Back-compat only. Don’t rely on this for reads at scale.
409
+ messages: [{ type: mongo.Schema.Types.ObjectId, ref: 'ConversationMessage' }],
410
+ },
411
+ {
412
+ indexes: [
413
+ // Inbox list (participant mailbox / DMs / etc.)
414
+ { fields: { 'participants.profileId': 1, lastMessageDate: -1 } },
415
+
416
+ // Filtered by kind (mail tab, dm tab, etc.)
417
+ { fields: { kind: 1, 'participants.profileId': 1, lastMessageDate: -1 } },
418
+
419
+ // Back-compat owner mailbox queries
420
+ { fields: { profileId: 1, kind: 1, lastMessageDate: -1 } },
421
+ {
422
+ fields: { key: 1, profileId: 1 },
423
+ options: {
424
+ unique: true,
425
+ partialFilterExpression: { profileId: { $type: 'objectId' } },
426
+ },
427
+ },
428
+ {
429
+ fields: { kind: 1, profileId: 1 },
430
+ options: {
431
+ unique: true,
432
+ partialFilterExpression: { profileId: { $type: 'objectId' } },
433
+ },
434
+ },
435
+
436
+ {
437
+ fields: { applicationId: 1, kind: 1, profileId: 1, key: 1 },
438
+ options: {
439
+ unique: true,
440
+ partialFilterExpression: { key: { $type: 'string' } },
441
+ },
442
+ },
443
+ ],
444
+ virtuals: [...addTagVirtuals('Conversation'), ...addApplicationVirtual()],
445
+ }
446
+ );
447
+
448
+ // =========================
449
+ // ConversationMessage (Message)
450
+ // =========================
451
+ //
452
+ // Key points:
453
+ // - Primary paging index is (conversationId, _id:-1).
454
+ // - Claim fields use claimedDate consistently.
455
+ // - Dedupe is per-conversation (compound) and unique when present.
456
+ // - Claimable listing inside a conversation has a supporting index.
457
+ //
458
+ export const ConversationMessage = createModel<Types.ConversationMessageDocument>(
459
+ 'ConversationMessage',
460
+ {
461
+ conversationId: { type: mongo.Schema.Types.ObjectId, ref: 'Conversation', required: true, index: true },
462
+
463
+ role: { type: String, enum: ['user', 'assistant', 'system'], required: true },
464
+
465
+ type: {
466
+ type: String,
467
+ enum: ['text', 'notice', 'reward', 'action', 'system'],
468
+ default: 'text',
469
+ index: true,
470
+ },
471
+
472
+ isStarred: { type: Boolean, default: false, index: true },
473
+
474
+ content: { type: String, default: '' },
475
+
476
+ payload: { type: mongo.Schema.Types.Mixed },
477
+
478
+ replyToId: { type: mongo.Schema.Types.ObjectId, ref: 'ConversationMessage' },
479
+
480
+ claim: {
481
+ isClaimable: { type: Boolean, default: false, index: true },
482
+
483
+ // ✅ normalized field names (match your latest applyPatchesOrMail.ts)
484
+ claimedDate: { type: Date, default: null },
485
+ claimedByProfileId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile', default: null },
486
+
487
+ dedupeKey: { type: String, default: null },
488
+
489
+ attachments: { type: [mongo.Schema.Types.Mixed], default: [] },
490
+
491
+ revokedDate: { type: Date, default: null },
492
+ revokeReason: { type: String, default: null },
493
+ },
494
+ },
495
+ {
496
+ indexes: [
497
+ // ✅ Primary paging for “latest messages”
498
+ { fields: { conversationId: 1, _id: -1 } },
499
+
500
+ // Optional (only if you actually sort by createdDate elsewhere)
501
+ { fields: { conversationId: 1, createdDate: -1 } },
502
+
503
+ // Claim listing scans (admin / analytics)
504
+ { fields: { 'claim.isClaimable': 1, 'claim.claimedDate': 1 } },
505
+
506
+ // Claim listing inside a conversation (UI list “claimable first”)
507
+ { fields: { conversationId: 1, 'claim.isClaimable': 1, 'claim.claimedDate': 1, _id: -1 } },
508
+
509
+ // Fast dedupe lookup per conversation
510
+ { fields: { conversationId: 1, 'claim.dedupeKey': 1 } },
511
+
512
+ // ✅ Enforce dedupeKey uniqueness per conversation when present
513
+ {
514
+ fields: { conversationId: 1, 'claim.dedupeKey': 1 },
515
+ options: {
516
+ unique: true,
517
+ partialFilterExpression: { 'claim.dedupeKey': { $type: 'string' } },
518
+ },
519
+ },
520
+
521
+ { fields: { isStarred: 1, conversationId: 1, _id: -1 } },
522
+ ],
523
+ virtuals: [...addTagVirtuals('ConversationMessage'), ...addApplicationVirtual()],
524
+ }
525
+ );
526
+
527
+ // Data Model
528
+ export const Data = createModel<Types.DataDocument>(
529
+ 'Data',
530
+ {
531
+ mod: { type: String, required: true },
532
+ },
533
+ {
534
+ virtuals: [...addTagVirtuals('Data'), ...addApplicationVirtual()],
535
+ }
536
+ );
537
+
538
+ export const Meta = createModel<Types.DataDocument>(
539
+ 'Meta',
540
+ {},
541
+ {
542
+ virtuals: [...addTagVirtuals('Meta'), ...addApplicationVirtual()],
543
+ }
544
+ );
545
+
546
+ // Discussion Model
547
+ export const Discussion = createModel<Types.DiscussionDocument>(
548
+ 'Discussion',
549
+ {
550
+ content: { type: String },
551
+ parentId: { type: mongo.Schema.Types.ObjectId, ref: 'Discussion' },
552
+ rootMessageId: { type: mongo.Schema.Types.ObjectId, ref: 'Message' },
553
+ type: { type: String, default: 'Discussion' },
554
+ },
555
+ {
556
+ virtuals: [...addTagVirtuals('Discussion'), ...addApplicationVirtual()],
557
+ }
558
+ );
559
+
560
+ // Energy Model
561
+ export const Energy = createModel<Types.EnergyDocument>(
562
+ 'Energy',
563
+ {},
564
+ {
565
+ virtuals: [...addTagVirtuals('Energy'), ...addApplicationVirtual()],
566
+ }
567
+ );
568
+
569
+ // Event Model
570
+ export const Event = createModel<Types.EventDocument>(
571
+ 'Event',
572
+ {},
573
+ {
574
+ virtuals: [...addTagVirtuals('Event'), ...addApplicationVirtual()],
575
+ }
576
+ );
577
+
578
+ // File Model
579
+ export const File = createModel<Types.FileDocument>(
580
+ 'File',
581
+ {
582
+ content: { type: String },
583
+ storageType: { type: String, max: 100 },
584
+ accessType: { type: String, max: 100 },
585
+ },
586
+ {
587
+ virtuals: [...addTagVirtuals('File'), ...addApplicationVirtual()],
588
+ }
589
+ );
590
+
591
+ // Galaxy Model
592
+ export const Galaxy = createModel<Types.GalaxyDocument>(
593
+ 'Galaxy',
594
+ {
595
+ universeId: { type: mongo.Schema.Types.ObjectId, ref: 'Universe' },
596
+ },
597
+ {
598
+ virtuals: [...addTagVirtuals('Galaxy'), ...addApplicationVirtual()],
599
+ }
600
+ );
601
+
602
+ // Guide Model
603
+ export const Guide = createModel<Types.GuideDocument>(
604
+ 'Guide',
605
+ {
606
+ content: { type: String },
607
+ gameId: { type: mongo.Schema.Types.ObjectId, ref: 'Game' },
608
+ attachments: [mongo.Schema.Types.Mixed],
609
+ },
610
+ {
611
+ virtuals: [...addTagVirtuals('Guide'), ...addApplicationVirtual()],
612
+ }
613
+ );
614
+
615
+ // Idea Model
616
+ export const Idea = createModel<Types.IdeaDocument>(
617
+ 'Idea',
618
+ {
619
+ type: { type: String, max: 100 },
620
+ communityId: { type: mongo.Schema.Types.ObjectId, ref: 'Community' },
621
+ },
622
+ {
623
+ virtuals: [...addTagVirtuals('Idea'), ...addApplicationVirtual()],
624
+ }
625
+ );
626
+
627
+ // Leaderboard Model
628
+ export const Leaderboard = createModel<Types.LeaderboardDocument>(
629
+ 'Leaderboard',
630
+ {
631
+ productId: { type: mongo.Schema.Types.ObjectId, ref: 'Product' },
632
+ },
633
+ {
634
+ virtuals: [...addTagVirtuals('Leaderboard'), ...addApplicationVirtual()],
635
+ }
636
+ );
637
+
638
+ // Log Model
639
+ export const Log = createModel<Types.LogDocument>(
640
+ 'Log',
641
+ {
642
+ mod: { type: String, required: true },
643
+ messages: [mongo.Schema.Types.Mixed],
644
+ // tags: [mongo.Schema.Types.Mixed],
645
+ },
646
+ {
647
+ virtuals: [...addTagVirtuals('Log'), ...addApplicationVirtual()],
648
+ }
649
+ );
650
+
651
+ // Lore Model
652
+ export const Lore = createModel<Types.LoreDocument>(
653
+ 'Lore',
654
+ {
655
+ gameId: { type: mongo.Schema.Types.ObjectId, ref: 'Game' },
656
+ },
657
+ {
658
+ virtuals: [...addTagVirtuals('Lore'), ...addApplicationVirtual()],
659
+ }
660
+ );
661
+
662
+ // Market Model
663
+ export const Market = createModel<Types.MarketDocument>(
664
+ 'Market',
665
+ {},
666
+ {
667
+ virtuals: [...addTagVirtuals('Market'), ...addApplicationVirtual()],
668
+ }
669
+ );
670
+
671
+ // Memory Model
672
+ export const Memory = createModel<Types.MemoryDocument>(
673
+ 'Memory',
674
+ {},
675
+ {
676
+ virtuals: [...addTagVirtuals('Memory'), ...addApplicationVirtual()],
677
+ }
678
+ );
679
+
680
+ // Message Model
681
+ export const Message = createModel<Types.MessageDocument>(
682
+ 'Message',
683
+ {
684
+ content: { type: String },
685
+ type: { type: String, max: 100 },
686
+ replyToId: { type: mongo.Schema.Types.ObjectId, ref: 'Message' },
687
+ parentId: { type: mongo.Schema.Types.ObjectId, ref: 'Message' },
688
+ conversationId: { type: mongo.Schema.Types.ObjectId, ref: 'Conversation' },
689
+ // messages: [{ type: mongo.Schema.Types.ObjectId, ref: 'Message' }],
690
+ },
691
+ {
692
+ virtuals: [...addTagVirtuals('Message'), ...addApplicationVirtual()],
693
+ }
694
+ );
695
+
696
+ // NewsArticle Model
697
+ export const NewsArticle = createModel<Types.NewsArticleDocument>(
698
+ 'NewsArticle',
699
+ {
700
+ href: { type: String, required: true },
701
+ source: { type: String, required: true },
702
+ },
703
+ {
704
+ virtuals: [...addTagVirtuals('NewsArticle'), ...addApplicationVirtual()],
705
+ }
706
+ );
707
+
708
+ // Npc Model
709
+ export const Npc = createModel<Types.NpcDocument>(
710
+ 'Npc',
711
+ {
712
+ characterId: { type: mongo.Schema.Types.ObjectId, ref: 'Character' },
713
+ },
714
+ {
715
+ virtuals: [...addTagVirtuals('Npc'), ...addApplicationVirtual()],
716
+ }
717
+ );
718
+
719
+ // Offer Model
720
+ export const Offer = createModel<Types.OfferDocument>(
721
+ 'Offer',
722
+ {},
723
+ {
724
+ virtuals: [...addTagVirtuals('Offer'), ...addApplicationVirtual()],
725
+ }
726
+ );
727
+
728
+ // Order Model
729
+ export const Order = createModel<Types.OrderDocument>(
730
+ 'Order',
731
+ {},
732
+ {
733
+ virtuals: [...addTagVirtuals('Order'), ...addApplicationVirtual()],
734
+ }
735
+ );
736
+
737
+ // Payment Model
738
+ export const Payment = createModel<Types.PaymentDocument>(
739
+ 'Payment',
740
+ {
741
+ status: {
742
+ type: String,
743
+ default: 'Submitted',
744
+ enum: [
745
+ 'Archived',
746
+ 'Processing',
747
+ 'Failed',
748
+ 'Submitted',
749
+ 'Denied',
750
+ 'Processed',
751
+ 'Voided',
752
+ 'Completed',
753
+ 'Refunding',
754
+ 'Refunded',
755
+ 'Expired',
756
+ ],
757
+ },
758
+ },
759
+ {
760
+ virtuals: [{ name: 'owner' }, ...addTagVirtuals('Payment'), ...addApplicationVirtual()],
761
+ }
762
+ );
763
+
764
+ // Permission Model
765
+ export const Permission = createModel<Types.PermissionDocument>(
766
+ 'Permission',
767
+ {
768
+ roles: [{ type: mongo.Schema.Types.ObjectId, ref: 'Role' }],
769
+ },
770
+ {
771
+ virtuals: [...addTagVirtuals('Permission'), ...addApplicationVirtual()],
772
+ }
773
+ );
774
+
775
+ // Person Model
776
+ export const Person = createModel<Types.PersonDocument>(
777
+ 'Person',
778
+ {
779
+ content: { type: String },
780
+ companyId: { type: mongo.Schema.Types.ObjectId, ref: 'Company' },
781
+ },
782
+ {
783
+ virtuals: [...addTagVirtuals('Person'), ...addApplicationVirtual()],
784
+ }
785
+ );
786
+
787
+ // Planet Model
788
+ export const Planet = createModel<Types.PlanetDocument>(
789
+ 'Planet',
790
+ {
791
+ solarSystemId: { type: mongo.Schema.Types.ObjectId, ref: 'SolarSystem' },
792
+ },
793
+ {
794
+ virtuals: [...addTagVirtuals('Planet'), ...addApplicationVirtual()],
795
+ }
796
+ );
797
+
798
+ // Poll Model
799
+ export const Poll = createModel<Types.PollDocument>(
800
+ 'Poll',
801
+ {},
802
+ {
803
+ virtuals: [...addTagVirtuals('Poll'), ...addApplicationVirtual()],
804
+ }
805
+ );
806
+
807
+ // Project Model
808
+ export const Project = createModel<Types.ProjectDocument>(
809
+ 'Project',
810
+ {
811
+ content: { type: String },
812
+ contractStatus: { type: String, default: 'Pending' },
813
+ parentId: { type: mongo.Schema.Types.ObjectId, ref: 'Project' },
814
+ realmId: { type: mongo.Schema.Types.ObjectId, ref: 'Realm' },
815
+ communityId: { type: mongo.Schema.Types.ObjectId, ref: 'Community' },
816
+ productId: { type: mongo.Schema.Types.ObjectId, ref: 'Product' },
817
+ ratingId: { type: mongo.Schema.Types.ObjectId, ref: 'Rating' },
818
+ },
819
+ {
820
+ virtuals: [...addTagVirtuals('Project'), ...addApplicationVirtual()],
821
+ }
822
+ );
823
+
824
+ // Proposal Model
825
+ export const Proposal = createModel<Types.ProposalDocument>(
826
+ 'Proposal',
827
+ {
828
+ content: { type: String },
829
+ },
830
+ {
831
+ virtuals: [...addTagVirtuals('Proposal'), ...addApplicationVirtual()],
832
+ }
833
+ );
834
+
835
+ // Quest Model
836
+ export const Quest = createModel<Types.QuestDocument>(
837
+ 'Quest',
838
+ {
839
+ type: { type: String, default: 'zone' },
840
+ },
841
+ {
842
+ virtuals: [...addTagVirtuals('Quest'), ...addApplicationVirtual()],
843
+ }
844
+ );
845
+
846
+ // Question Model
847
+ export const Question = createModel<Types.QuestionDocument>(
848
+ 'Question',
849
+ {
850
+ topics: [mongo.Schema.Types.Mixed],
851
+ text: { type: String, required: true },
852
+ answer: { type: String, required: true },
853
+ popularity: { type: Number },
854
+ },
855
+ {
856
+ virtuals: [...addTagVirtuals('Question'), ...addApplicationVirtual()],
857
+ }
858
+ );
859
+
860
+ // Rating Model
861
+ export const Rating = createModel<Types.RatingDocument>(
862
+ 'Rating',
863
+ {
864
+ votes: [{ type: mongo.Schema.Types.ObjectId, ref: 'Vote' }],
865
+ },
866
+ {
867
+ virtuals: [...addTagVirtuals('Rating'), ...addApplicationVirtual()],
868
+ }
869
+ );
870
+
871
+ // Realm Model
872
+ export const Realm = createModel<Types.RealmDocument>(
873
+ 'Realm',
874
+ {
875
+ endpoint: { type: String },
876
+ status: { type: String },
877
+ clientCount: { type: Number },
878
+ regionCode: { type: String },
879
+ gameId: { type: mongo.Schema.Types.ObjectId, ref: 'Game', required: true },
880
+ },
881
+ {
882
+ virtuals: [
883
+ ...addTagVirtuals('Realm'),
884
+ ...addApplicationVirtual(),
885
+ { name: 'realmShards' },
886
+ { name: 'realmTraits' },
887
+ { name: 'realmEvents' },
888
+ ],
889
+ }
890
+ );
891
+
892
+ // RealmEvent Model
893
+ export const RealmEvent = createModel<Types.RealmEventDocument>(
894
+ 'RealmEvent',
895
+ {
896
+ description: { type: String, required: true },
897
+ startDate: { type: Date, required: false },
898
+ endDate: { type: Date, required: false },
899
+ },
900
+ {
901
+ virtuals: [...addTagVirtuals('RealmEvent'), ...addApplicationVirtual()],
902
+ }
903
+ );
904
+
905
+ // RealmTrait Model
906
+ export const RealmTrait = createModel<Types.RealmTraitDocument>(
907
+ 'RealmTrait',
908
+ {
909
+ description: { type: String, required: true },
910
+ },
911
+ {
912
+ virtuals: [...addTagVirtuals('RealmTrait'), ...addApplicationVirtual()],
913
+ }
914
+ );
915
+
916
+ // Referral Model
917
+ export const Referral = createModel<Types.ReferralDocument>(
918
+ 'Referral',
919
+ {
920
+ recipientId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile', required: true },
921
+ senderId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile', required: true },
922
+ },
923
+ {
924
+ virtuals: [...addTagVirtuals('Referral'), ...addApplicationVirtual()],
925
+ }
926
+ );
927
+
928
+ // Review Model
929
+ export const Review = createModel<Types.ReviewDocument>(
930
+ 'Review',
931
+ {
932
+ value: { type: String },
933
+ },
934
+ {
935
+ virtuals: [...addTagVirtuals('Review'), ...addApplicationVirtual()],
936
+ }
937
+ );
938
+
939
+ // Role Model
940
+ export const Role = createModel<Types.RoleDocument>(
941
+ 'Role',
942
+ {
943
+ value: { type: String },
944
+ profiles: [{ type: mongo.Schema.Types.ObjectId, ref: 'Profile' }],
945
+ permissions: [{ type: mongo.Schema.Types.ObjectId, ref: 'Permission' }],
946
+ },
947
+ {
948
+ virtuals: [...addTagVirtuals('Role'), ...addApplicationVirtual()],
949
+ }
950
+ );
951
+
952
+ // Season Model
953
+ export const Season = createModel<Types.SeasonDocument>(
954
+ 'Season',
955
+ {},
956
+ {
957
+ virtuals: [...addTagVirtuals('Season'), ...addApplicationVirtual()],
958
+ }
959
+ );
960
+
961
+ // RealmShard Model
962
+ export const RealmShard = createModel<Types.RealmShardDocument>(
963
+ 'RealmShard',
964
+ {
965
+ realmId: { type: mongo.Schema.Types.ObjectId, ref: 'Realm' },
966
+ endpoint: { type: String },
967
+ status: { type: String },
968
+ clientCount: { type: Number },
969
+ },
970
+ {
971
+ virtuals: [...addTagVirtuals('RealmShard'), ...addApplicationVirtual()],
972
+ }
973
+ );
974
+
975
+ // Session Model
976
+ export const Session = createModel<Types.SessionDocument>(
977
+ 'Session',
978
+ {
979
+ expired: { type: Date, required: true },
980
+ },
981
+ {
982
+ virtuals: [...addTagVirtuals('Session'), ...addApplicationVirtual()],
983
+ }
984
+ );
985
+
986
+ // SolarSystem Model
987
+ export const SolarSystem = createModel<Types.SolarSystemDocument>(
988
+ 'SolarSystem',
989
+ {
990
+ galaxyId: { type: mongo.Schema.Types.ObjectId, ref: 'Galaxy' },
991
+ },
992
+ {
993
+ virtuals: [...addTagVirtuals('SolarSystem'), ...addApplicationVirtual()],
994
+ }
995
+ );
996
+
997
+ // Star Model
998
+ export const Star = createModel<Types.StarDocument>(
999
+ 'Star',
1000
+ {},
1001
+ {
1002
+ virtuals: [...addTagVirtuals('Star'), ...addApplicationVirtual()],
1003
+ }
1004
+ );
1005
+
1006
+ // Stat Model
1007
+ export const Stat = createModel<Types.StatDocument>(
1008
+ 'Stat',
1009
+ {
1010
+ number: { type: Number, default: 0 },
1011
+ },
1012
+ {
1013
+ virtuals: [...addTagVirtuals('Stat'), ...addApplicationVirtual()],
1014
+ }
1015
+ );
1016
+
1017
+ // Stash Model
1018
+ export const Stash = createModel<Types.StashDocument>(
1019
+ 'Stash',
1020
+ {},
1021
+ {
1022
+ virtuals: [...addTagVirtuals('Stash'), ...addApplicationVirtual()],
1023
+ }
1024
+ );
1025
+
1026
+ // Stock Model
1027
+ export const Stock = createModel<Types.StockDocument>(
1028
+ 'Stock',
1029
+ {
1030
+ rank: { type: Number, min: 0 },
1031
+ price: { type: Number, min: 0 },
1032
+ hourChange: { type: Number },
1033
+ dayChange: { type: Number },
1034
+ weekChange: { type: Number },
1035
+ marketCap: { type: Number, min: 0 },
1036
+ volume: { type: Number, min: 0 },
1037
+ ticker: { type: String },
1038
+ unusualActivity: { type: Number, min: 0 },
1039
+ },
1040
+ {
1041
+ virtuals: [...addTagVirtuals('Stock'), ...addApplicationVirtual()],
1042
+ }
1043
+ );
1044
+
1045
+ // Suggestion Model
1046
+ export const Suggestion = createModel<Types.SuggestionDocument>(
1047
+ 'Suggestion',
1048
+ {
1049
+ content: { type: String },
1050
+ },
1051
+ {
1052
+ virtuals: [...addTagVirtuals('Suggestion'), ...addApplicationVirtual()],
1053
+ }
1054
+ );
1055
+
1056
+ // Tag Model
1057
+ export const Tag = createModel<Types.TagDocument>(
1058
+ 'Tag',
1059
+ {
1060
+ value: { type: String },
1061
+ },
1062
+ {
1063
+ virtuals: [...addApplicationVirtual()],
1064
+ }
1065
+ );
1066
+
1067
+ // Team Model
1068
+ export const Team = createModel<Types.TeamDocument>(
1069
+ 'Team',
1070
+ {
1071
+ ratingId: { type: mongo.Schema.Types.ObjectId, ref: 'Rating' },
1072
+ points: { type: Number, default: 0 },
1073
+ memberCount: { type: Number, default: 0 },
1074
+ },
1075
+ {
1076
+ virtuals: [
1077
+ ...addTagVirtuals('Team'),
1078
+ ...addApplicationVirtual(),
1079
+ {
1080
+ name: 'profiles',
1081
+ ref: 'Profile',
1082
+ localField: '_id',
1083
+ foreignField: 'teamId',
1084
+ },
1085
+ ],
1086
+ }
1087
+ );
1088
+
1089
+ // Tournament Model
1090
+ export const Tournament = createModel<Types.TournamentDocument>(
1091
+ 'Tournament',
1092
+ {},
1093
+ {
1094
+ virtuals: [...addTagVirtuals('Tournament'), ...addApplicationVirtual()],
1095
+ }
1096
+ );
1097
+
1098
+ // Trade Model
1099
+ export const Trade = createModel<Types.TradeDocument>(
1100
+ 'Trade',
1101
+ {
1102
+ status: {
1103
+ type: String,
1104
+ default: 'Active',
1105
+ enum: ['Paused', 'Pending', 'Active', 'Delisted', 'Sold'],
1106
+ },
1107
+ chainId: { type: mongo.Schema.Types.ObjectId, ref: 'Chain' },
1108
+ buyerId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile' },
1109
+ parentId: { type: mongo.Schema.Types.ObjectId, ref: 'Trade' },
1110
+ productId: { type: mongo.Schema.Types.ObjectId, ref: 'Product' },
1111
+ sellerId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile' },
1112
+ tokenId: { type: mongo.Schema.Types.ObjectId, ref: 'ChainToken' },
1113
+ },
1114
+ {
1115
+ virtuals: [...addTagVirtuals('Trade'), ...addApplicationVirtual()],
1116
+ }
1117
+ );
1118
+
1119
+ // Universe Model
1120
+ export const Universe = createModel<Types.UniverseDocument>(
1121
+ 'Universe',
1122
+ {},
1123
+ {
1124
+ virtuals: [...addTagVirtuals('Universe'), ...addApplicationVirtual()],
1125
+ }
1126
+ );
1127
+
1128
+ // Validator Model
1129
+ export const Validator = createModel<Types.ValidatorDocument>(
1130
+ 'Validator',
1131
+ {},
1132
+ {
1133
+ virtuals: [...addTagVirtuals('Validator'), ...addApplicationVirtual()],
1134
+ }
1135
+ );
1136
+
1137
+ // Vote Model
1138
+ export const Vote = createModel<Types.VoteDocument>(
1139
+ 'Vote',
1140
+ {
1141
+ ratingId: { type: mongo.Schema.Types.ObjectId, ref: 'Rating' },
1142
+ },
1143
+ {
1144
+ virtuals: [
1145
+ {
1146
+ name: 'parent',
1147
+ ref: 'Node',
1148
+ localField: '_id',
1149
+ foreignField: 'from',
1150
+ justOne: true,
1151
+ match: { fromModel: 'Vote' },
1152
+ },
1153
+ {
1154
+ name: 'owner',
1155
+ ref: 'Profile',
1156
+ localField: '_id',
1157
+ foreignField: '_id',
1158
+ justOne: true,
1159
+ },
1160
+ ...addTagVirtuals('Vote'),
1161
+ ...addApplicationVirtual(),
1162
+ ],
1163
+ }
1164
+ );
1165
+
1166
+ // WorldEvent Model
1167
+ export const WorldEvent = createModel<Types.WorldEventDocument>(
1168
+ 'WorldEvent',
1169
+ {
1170
+ text: { type: String, required: true },
1171
+ importance: { type: Number },
1172
+ // tags: [mongo.Schema.Types.Mixed],
1173
+ },
1174
+ {
1175
+ virtuals: [...addTagVirtuals('WorldEvent'), ...addApplicationVirtual()],
1176
+ }
1177
+ );
1178
+
1179
+ // WorldRecord Model
1180
+ export const WorldRecord = createModel<Types.WorldRecordDocument>(
1181
+ 'WorldRecord',
1182
+ {
1183
+ holderId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile' },
1184
+ score: { type: Number },
1185
+ // tags: [mongo.Schema.Types.Mixed],
1186
+ },
1187
+ {
1188
+ virtuals: [
1189
+ {
1190
+ name: 'holder',
1191
+ ref: 'Profile',
1192
+ localField: '_id',
1193
+ foreignField: '_id',
1194
+ justOne: true,
1195
+ },
1196
+ ...addTagVirtuals('WorldRecord'),
1197
+ ...addApplicationVirtual(),
1198
+ ],
1199
+ }
1200
+ );
1201
+
1202
+ // Node Model (for polymorphic relationships)
1203
+ export const Node = createModel<Types.NodeDocument>(
1204
+ 'Node',
1205
+ {
1206
+ relationKey: { type: String, required: true },
1207
+ fromModel: { type: String, required: true },
1208
+ from: { type: mongo.Schema.Types.ObjectId, required: true },
1209
+ toModel: { type: String, required: true },
1210
+ to: { type: mongo.Schema.Types.ObjectId, required: true },
1211
+ },
1212
+ {
1213
+ indexes: [
1214
+ { fromModel: 1, from: 1 },
1215
+ { toModel: 1, to: 1 },
1216
+ ],
1217
+ }
1218
+ );
1219
+
1220
+ export const Prefab = createModel<Types.PrefabDocument>(
1221
+ 'Prefab',
1222
+ {
1223
+ name: { type: String, required: true },
1224
+ fbxPath: { type: String, required: true },
1225
+ customizationOptions: { type: mongo.Schema.Types.Mixed }, // e.g., color, scale range, etc.
1226
+ childPrefabs: [
1227
+ {
1228
+ prefabId: { type: mongo.Schema.Types.ObjectId, ref: 'Prefab' },
1229
+ position: { type: mongo.Schema.Types.Mixed }, // Relative position within parent prefab
1230
+ rotation: { type: mongo.Schema.Types.Mixed },
1231
+ scale: { type: Number, default: 1.0 },
1232
+ },
1233
+ ],
1234
+ },
1235
+ {
1236
+ extend: 'EntityFields',
1237
+ virtuals: [...addTagVirtuals('Prefab'), ...addApplicationVirtual()],
1238
+ }
1239
+ );
1240
+
1241
+ export const Object = createModel<Types.ObjectDocument>(
1242
+ 'Object',
1243
+ {
1244
+ prefabId: { type: mongo.Schema.Types.ObjectId, ref: 'Prefab', required: true },
1245
+ // profileId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile', required: true },
1246
+ // worldCoordinates: {
1247
+ // x: { type: Number, required: true },
1248
+ // y: { type: Number, required: true },
1249
+ // z: { type: Number, required: true },
1250
+ // },
1251
+ rotation: { type: mongo.Schema.Types.Mixed },
1252
+ scale: { type: Number, default: 1.0 },
1253
+ customizations: { type: mongo.Schema.Types.Mixed },
1254
+ childInstances: [
1255
+ {
1256
+ prefabId: { type: mongo.Schema.Types.ObjectId, ref: 'Prefab' },
1257
+ worldCoordinates: { type: mongo.Schema.Types.Mixed },
1258
+ rotation: { type: mongo.Schema.Types.Mixed },
1259
+ scale: { type: Number, default: 1.0 },
1260
+ },
1261
+ ],
1262
+ },
1263
+ {
1264
+ extend: 'EntityFields',
1265
+ virtuals: [...addTagVirtuals('Object'), ...addApplicationVirtual()],
1266
+ }
1267
+ );
1268
+
1269
+ export const ObjectInteraction = createModel<Types.ObjectInteractionDocument>(
1270
+ 'ObjectInteraction',
1271
+ {
1272
+ profileId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile', required: true },
1273
+ objectId: { type: mongo.Schema.Types.ObjectId, ref: 'Object', required: true },
1274
+ interactionType: { type: String, enum: ['use', 'fight', 'open', 'talk'], required: true },
1275
+ outcome: { type: mongo.Schema.Types.Mixed },
1276
+ // timestamp: { type: Date, default: Date.now },
1277
+ },
1278
+ {
1279
+ extend: 'EntityFields',
1280
+ virtuals: [...addTagVirtuals('Interaction'), ...addApplicationVirtual()],
1281
+ }
1282
+ );
1283
+
1284
+ // Party Model
1285
+ export const Party = createModel<Types.PartyDocument>(
1286
+ 'Party',
1287
+ {
1288
+ targetAreaId: { type: mongo.Schema.Types.ObjectId, ref: 'Area', required: false }, // Adjust 'Area' to actual collection if known
1289
+ limit: { type: Number, default: 6 },
1290
+ isPublic: { type: Boolean, default: true },
1291
+ isVisibleToEnemies: { type: Boolean, default: true },
1292
+ isApprovalRequired: { type: Boolean, default: false },
1293
+ isNonLeaderInviteAllowed: { type: Boolean, default: false },
1294
+ isCombatEnabled: { type: Boolean, default: true },
1295
+ isFriendlyFireEnabled: { type: Boolean, default: true },
1296
+ isLocalQuestShared: { type: Boolean, default: true },
1297
+ isGlobalQuestShared: { type: Boolean, default: true },
1298
+ isMergeEnabled: { type: Boolean, default: false },
1299
+ isRejoinEnabled: { type: Boolean, default: false },
1300
+ itemDistribution: {
1301
+ type: String,
1302
+ enum: ['Random', 'Personal'],
1303
+ required: true,
1304
+ },
1305
+ leaderId: { type: mongo.Schema.Types.ObjectId, ref: 'Profile', required: false }, // Adjust 'Profile' to actual collection if known
1306
+ powerRequired: { type: Number, required: true, default: 1 },
1307
+ levelRequired: { type: Number, required: true, default: 1 },
1308
+ approvalMethod: {
1309
+ type: String,
1310
+ enum: ['Auto Accept', 'Approval Required'],
1311
+ required: true,
1312
+ },
1313
+ memberIds: [{ type: mongo.Schema.Types.ObjectId, ref: 'Profile' }], // Adjust 'Profile' if necessary
1314
+ assistantIds: [{ type: mongo.Schema.Types.ObjectId, ref: 'Profile' }],
1315
+ pendingMemberIds: [{ type: mongo.Schema.Types.ObjectId, ref: 'Profile' }],
1316
+ blockedMemberIds: [{ type: mongo.Schema.Types.ObjectId, ref: 'Profile' }],
1317
+ },
1318
+ {
1319
+ virtuals: [
1320
+ { name: 'owner' },
1321
+ {
1322
+ name: 'members',
1323
+ ref: 'Profile',
1324
+ localField: '_id',
1325
+ foreignField: 'partyId',
1326
+ },
1327
+ ...addTagVirtuals('Party'),
1328
+ ...addApplicationVirtual(),
1329
+ ],
1330
+ }
1331
+ );
1332
+
1333
+ export const SeerEvent = mongo.createModel<Types.SeerEventDocument>(
1334
+ 'SeerEvent',
1335
+ {
1336
+ kind: { type: String, required: true }, // model name: 'Character', 'Item', etc.
1337
+ operation: {
1338
+ type: String,
1339
+ enum: ['create', 'update', 'delete'],
1340
+ required: true,
1341
+ },
1342
+ recordId: { type: String, required: true },
1343
+ applicationId: { type: mongo.Schema.Types.ObjectId, ref: 'Application' },
1344
+
1345
+ // ✅ this is the important fix: schema *object* with `type: Mixed`
1346
+ payload: { type: mongo.Schema.Types.Mixed, required: true },
1347
+
1348
+ seq: { type: Number, required: true, index: true },
1349
+ timestamp: { type: Date, default: Date.now, index: true },
1350
+ },
1351
+ {
1352
+ // extend: 'CommonFields', // or 'EntityFields' if you want applicationId/ownerId, but you already have applicationId above
1353
+ indexes: [{ seq: 1 }, { timestamp: 1 }],
1354
+ }
1355
+ );
1356
+
1357
+ export const SeerPayload = mongo.createModel<Types.SeerPayloadDocument>(
1358
+ 'SeerPayload',
1359
+ {
1360
+ fromSeer: { type: String, required: true },
1361
+ applicationId: { type: mongo.Schema.Types.ObjectId, ref: 'Application' },
1362
+
1363
+ // list of raw events we snapshot
1364
+ // TS doesn't love `[Mixed]`, so we cast this field only
1365
+ events: {
1366
+ type: [mongo.Schema.Types.Mixed],
1367
+ default: [],
1368
+ } as any,
1369
+
1370
+ eventsHash: { type: String, required: true },
1371
+ merkleRoot: { type: String, required: true },
1372
+
1373
+ proof: { type: mongo.Schema.Types.Mixed, required: true },
1374
+ publicSignals: { type: [String], default: [] },
1375
+ },
1376
+ {
1377
+ // extend: 'CommonFields',
1378
+ indexes: [{ createdDate: 1 }],
1379
+ }
1380
+ );