@nlabs/metropolisjs 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/.github/copilot-instructions.md +167 -0
  2. package/AGENTS.md +13 -0
  3. package/CHANGELOG.md +112 -0
  4. package/GRAPHQL_VALIDATION_RESULTS.md +158 -0
  5. package/PERMISSION_GRAPHQL_INTEGRATION.md +293 -0
  6. package/PERMISSION_IMPLEMENTATION_SUMMARY.md +243 -0
  7. package/README.md +1123 -112
  8. package/SIGNIN_GRAPHQL_VALIDATION.md +125 -0
  9. package/VAULT_GRAPHQL_API_FINDINGS.md +312 -0
  10. package/docs/ACTIONS.md +63 -0
  11. package/docs/COLLECTIONS.md +1038 -0
  12. package/docs/CONNECTIONS.md +1367 -0
  13. package/docs/CRUD_INTEGRATION.md +702 -0
  14. package/examples/connections-usage.tsx +909 -0
  15. package/examples/content-actions-usage.ts +144 -0
  16. package/examples/crud-usage.tsx +847 -0
  17. package/examples/extensibility-usage.tsx +889 -0
  18. package/examples/i18n-import-examples.ts +86 -0
  19. package/examples/i18n-namespace-usage.ts +118 -0
  20. package/examples/i18next-singleton-demo.ts +187 -0
  21. package/examples/permission-system-usage.tsx +415 -0
  22. package/examples/project-details.tsx +397 -0
  23. package/examples/shared-i18n-usage.tsx +203 -0
  24. package/examples/signup-error-handling.ts +100 -0
  25. package/examples/translation-types.ts +86 -0
  26. package/examples/translation-usage.tsx +336 -0
  27. package/index.js +1 -0
  28. package/jest.config.mjs +28 -0
  29. package/lex.config.mjs +11 -2
  30. package/lib/__tests__/e2e/helpers/testGraphQLServer.d.ts +22 -0
  31. package/lib/__tests__/e2e/helpers/testGraphQLServer.d.ts.map +1 -0
  32. package/lib/__tests__/e2e/helpers/testGraphQLServer.js +197 -0
  33. package/lib/__tests__/e2e/helpers/testGraphQLServerSimple.d.ts +3 -0
  34. package/lib/__tests__/e2e/helpers/testGraphQLServerSimple.d.ts.map +1 -0
  35. package/lib/__tests__/e2e/helpers/testGraphQLServerSimple.js +52 -0
  36. package/lib/actions/appActions/appActions.d.ts +29 -0
  37. package/lib/actions/appActions/appActions.d.ts.map +1 -0
  38. package/lib/actions/appActions/appActions.js +159 -0
  39. package/lib/actions/connectionActions/connectionActions.d.ts +19 -0
  40. package/lib/actions/connectionActions/connectionActions.d.ts.map +1 -0
  41. package/lib/actions/connectionActions/connectionActions.js +131 -0
  42. package/lib/actions/contentActions/contentActions.d.ts +34 -0
  43. package/lib/actions/contentActions/contentActions.d.ts.map +1 -0
  44. package/lib/actions/contentActions/contentActions.js +314 -0
  45. package/lib/actions/conversationActions/conversationActions.d.ts +30 -0
  46. package/lib/actions/conversationActions/conversationActions.d.ts.map +1 -0
  47. package/lib/actions/conversationActions/conversationActions.js +225 -0
  48. package/lib/actions/eventActions/eventActions.d.ts +27 -7
  49. package/lib/actions/eventActions/eventActions.d.ts.map +1 -0
  50. package/lib/actions/eventActions/eventActions.js +436 -2
  51. package/lib/actions/groupActions/groupActions.d.ts +30 -0
  52. package/lib/actions/groupActions/groupActions.d.ts.map +1 -0
  53. package/lib/actions/groupActions/groupActions.js +229 -0
  54. package/lib/actions/imageActions/imageActions.d.ts +16 -10
  55. package/lib/actions/imageActions/imageActions.d.ts.map +1 -0
  56. package/lib/actions/imageActions/imageActions.js +593 -2
  57. package/lib/actions/index.d.ts +21 -9
  58. package/lib/actions/index.d.ts.map +1 -0
  59. package/lib/actions/index.js +22 -2
  60. package/lib/actions/locationActions/locationActions.d.ts +11 -9
  61. package/lib/actions/locationActions/locationActions.d.ts.map +1 -0
  62. package/lib/actions/locationActions/locationActions.js +388 -2
  63. package/lib/actions/messageActions/messageActions.d.ts +16 -32
  64. package/lib/actions/messageActions/messageActions.d.ts.map +1 -0
  65. package/lib/actions/messageActions/messageActions.js +235 -2
  66. package/lib/actions/permissionActions/permissionActions.d.ts +34 -0
  67. package/lib/actions/permissionActions/permissionActions.d.ts.map +1 -0
  68. package/lib/actions/permissionActions/permissionActions.js +330 -0
  69. package/lib/actions/personaActions/personaActions.d.ts +65 -0
  70. package/lib/actions/personaActions/personaActions.d.ts.map +1 -0
  71. package/lib/actions/personaActions/personaActions.js +572 -0
  72. package/lib/actions/postActions/postActions.d.ts +12 -32
  73. package/lib/actions/postActions/postActions.d.ts.map +1 -0
  74. package/lib/actions/postActions/postActions.js +447 -2
  75. package/lib/actions/reactionActions/reactionActions.d.ts +13 -27
  76. package/lib/actions/reactionActions/reactionActions.d.ts.map +1 -0
  77. package/lib/actions/reactionActions/reactionActions.js +413 -2
  78. package/lib/actions/sseActions/sseActions.d.ts +1 -0
  79. package/lib/actions/sseActions/sseActions.d.ts.map +1 -0
  80. package/lib/actions/sseActions/sseActions.js +148 -2
  81. package/lib/actions/subscriptionActions/subscriptionActions.d.ts +24 -0
  82. package/lib/actions/subscriptionActions/subscriptionActions.d.ts.map +1 -0
  83. package/lib/actions/subscriptionActions/subscriptionActions.js +329 -0
  84. package/lib/actions/tagActions/tagActions.d.ts +13 -31
  85. package/lib/actions/tagActions/tagActions.d.ts.map +1 -0
  86. package/lib/actions/tagActions/tagActions.js +347 -2
  87. package/lib/actions/translationActions/translationActions.d.ts +38 -0
  88. package/lib/actions/translationActions/translationActions.d.ts.map +1 -0
  89. package/lib/actions/translationActions/translationActions.js +189 -0
  90. package/lib/actions/userActions/userActions.d.ts +42 -95
  91. package/lib/actions/userActions/userActions.d.ts.map +1 -0
  92. package/lib/actions/userActions/userActions.js +844 -2
  93. package/lib/actions/videoActions/videoActions.d.ts +41 -0
  94. package/lib/actions/videoActions/videoActions.d.ts.map +1 -0
  95. package/lib/actions/videoActions/videoActions.js +532 -0
  96. package/lib/actions/websocketActions/websocketActions.d.ts +20 -21
  97. package/lib/actions/websocketActions/websocketActions.d.ts.map +1 -0
  98. package/lib/actions/websocketActions/websocketActions.js +377 -2
  99. package/lib/adapters/appAdapter/appAdapter.d.ts +8 -0
  100. package/lib/adapters/appAdapter/appAdapter.d.ts.map +1 -0
  101. package/lib/adapters/appAdapter/appAdapter.js +90 -0
  102. package/lib/adapters/arangoAdapter/arangoAdapter.d.ts +3 -2
  103. package/lib/adapters/arangoAdapter/arangoAdapter.d.ts.map +1 -0
  104. package/lib/adapters/arangoAdapter/arangoAdapter.js +75 -2
  105. package/lib/adapters/contentAdapter/contentAdapter.d.ts +3 -2
  106. package/lib/adapters/contentAdapter/contentAdapter.d.ts.map +1 -0
  107. package/lib/adapters/contentAdapter/contentAdapter.js +107 -2
  108. package/lib/adapters/conversationAdapter/conversationAdapter.d.ts +3 -2
  109. package/lib/adapters/conversationAdapter/conversationAdapter.d.ts.map +1 -0
  110. package/lib/adapters/conversationAdapter/conversationAdapter.js +75 -2
  111. package/lib/adapters/eventAdapter/eventAdapter.d.ts +5 -2
  112. package/lib/adapters/eventAdapter/eventAdapter.d.ts.map +1 -0
  113. package/lib/adapters/eventAdapter/eventAdapter.js +162 -2
  114. package/lib/adapters/fileAdapter/fileAdapter.d.ts +3 -2
  115. package/lib/adapters/fileAdapter/fileAdapter.d.ts.map +1 -0
  116. package/lib/adapters/fileAdapter/fileAdapter.js +118 -2
  117. package/lib/adapters/groupAdapter/groupAdapter.d.ts +28 -0
  118. package/lib/adapters/groupAdapter/groupAdapter.d.ts.map +1 -0
  119. package/lib/adapters/groupAdapter/groupAdapter.js +66 -0
  120. package/lib/adapters/imageAdapter/imageAdapter.d.ts +9 -2
  121. package/lib/adapters/imageAdapter/imageAdapter.d.ts.map +1 -0
  122. package/lib/adapters/imageAdapter/imageAdapter.js +134 -2
  123. package/lib/adapters/index.d.ts +34 -16
  124. package/lib/adapters/index.d.ts.map +1 -0
  125. package/lib/adapters/index.js +19 -2
  126. package/lib/adapters/locationAdapter/locationAdapter.d.ts +3 -2
  127. package/lib/adapters/locationAdapter/locationAdapter.d.ts.map +1 -0
  128. package/lib/adapters/locationAdapter/locationAdapter.js +95 -2
  129. package/lib/adapters/messageAdapter/messageAdapter.d.ts +23 -19
  130. package/lib/adapters/messageAdapter/messageAdapter.d.ts.map +1 -0
  131. package/lib/adapters/messageAdapter/messageAdapter.js +82 -2
  132. package/lib/adapters/permissionAdapter/permissionAdapter.d.ts +41 -0
  133. package/lib/adapters/permissionAdapter/permissionAdapter.d.ts.map +1 -0
  134. package/lib/adapters/permissionAdapter/permissionAdapter.js +120 -0
  135. package/lib/adapters/personaAdapter/personaAdapter.d.ts +28 -2
  136. package/lib/adapters/personaAdapter/personaAdapter.d.ts.map +1 -0
  137. package/lib/adapters/personaAdapter/personaAdapter.js +161 -2
  138. package/lib/adapters/postAdapter/postAdapter.d.ts +3 -2
  139. package/lib/adapters/postAdapter/postAdapter.d.ts.map +1 -0
  140. package/lib/adapters/postAdapter/postAdapter.js +115 -2
  141. package/lib/adapters/reactionAdapter/reactionAdapter.d.ts +5 -2
  142. package/lib/adapters/reactionAdapter/reactionAdapter.d.ts.map +1 -0
  143. package/lib/adapters/reactionAdapter/reactionAdapter.js +81 -2
  144. package/lib/adapters/reaktorAdapter/reaktorAdapter.d.ts +3 -2
  145. package/lib/adapters/reaktorAdapter/reaktorAdapter.d.ts.map +1 -0
  146. package/lib/adapters/reaktorAdapter/reaktorAdapter.js +58 -2
  147. package/lib/adapters/sessionAdapter/sessionAdapter.d.ts +3 -2
  148. package/lib/adapters/sessionAdapter/sessionAdapter.d.ts.map +1 -0
  149. package/lib/adapters/sessionAdapter/sessionAdapter.js +80 -2
  150. package/lib/adapters/tagAdapter/tagAdapter.d.ts +3 -2
  151. package/lib/adapters/tagAdapter/tagAdapter.d.ts.map +1 -0
  152. package/lib/adapters/tagAdapter/tagAdapter.js +98 -2
  153. package/lib/adapters/translationAdapter/translationAdapter.d.ts +21 -0
  154. package/lib/adapters/translationAdapter/translationAdapter.d.ts.map +1 -0
  155. package/lib/adapters/translationAdapter/translationAdapter.js +55 -0
  156. package/lib/adapters/userAdapter/userAdapter.d.ts +18 -6
  157. package/lib/adapters/userAdapter/userAdapter.d.ts.map +1 -0
  158. package/lib/adapters/userAdapter/userAdapter.js +302 -2
  159. package/lib/adapters/videoAdapter/videoAdapter.d.ts +8 -0
  160. package/lib/adapters/videoAdapter/videoAdapter.d.ts.map +1 -0
  161. package/lib/adapters/videoAdapter/videoAdapter.js +194 -0
  162. package/lib/config/index.d.ts +19 -6
  163. package/lib/config/index.d.ts.map +1 -0
  164. package/lib/config/index.js +97 -2
  165. package/lib/constants/Collections.d.ts +44 -0
  166. package/lib/constants/Collections.d.ts.map +1 -0
  167. package/lib/constants/Collections.js +40 -0
  168. package/lib/constants/MetropolisConstants.d.ts +1 -0
  169. package/lib/constants/MetropolisConstants.d.ts.map +1 -0
  170. package/lib/constants/MetropolisConstants.js +15 -2
  171. package/lib/graphql/message.d.ts +1 -0
  172. package/lib/graphql/message.d.ts.map +1 -0
  173. package/lib/graphql/message.js +6 -4
  174. package/lib/graphql/notification.d.ts +1 -0
  175. package/lib/graphql/notification.d.ts.map +1 -0
  176. package/lib/graphql/notification.js +6 -4
  177. package/lib/graphql/session.d.ts +1 -0
  178. package/lib/graphql/session.d.ts.map +1 -0
  179. package/lib/graphql/session.js +4 -3
  180. package/lib/index.d.ts +45 -22
  181. package/lib/index.d.ts.map +1 -0
  182. package/lib/index.js +248 -2
  183. package/lib/stores/appStore.d.ts +1 -0
  184. package/lib/stores/appStore.d.ts.map +1 -0
  185. package/lib/stores/appStore.js +23 -2
  186. package/lib/stores/contentStore.d.ts +36 -0
  187. package/lib/stores/contentStore.d.ts.map +1 -0
  188. package/lib/stores/contentStore.js +139 -0
  189. package/lib/stores/conversationStore.d.ts +38 -0
  190. package/lib/stores/conversationStore.d.ts.map +1 -0
  191. package/lib/stores/conversationStore.js +117 -0
  192. package/lib/stores/eventStore.d.ts +4 -1
  193. package/lib/stores/eventStore.d.ts.map +1 -0
  194. package/lib/stores/eventStore.js +47 -2
  195. package/lib/stores/groupStore.d.ts +37 -0
  196. package/lib/stores/groupStore.d.ts.map +1 -0
  197. package/lib/stores/groupStore.js +68 -0
  198. package/lib/stores/imageStore.d.ts +6 -1
  199. package/lib/stores/imageStore.d.ts.map +1 -0
  200. package/lib/stores/imageStore.js +53 -2
  201. package/lib/stores/index.d.ts +20 -11
  202. package/lib/stores/index.d.ts.map +1 -0
  203. package/lib/stores/index.js +24 -2
  204. package/lib/stores/locationStore.d.ts +2 -1
  205. package/lib/stores/locationStore.d.ts.map +1 -0
  206. package/lib/stores/locationStore.js +42 -2
  207. package/lib/stores/messageStore.d.ts +19 -4
  208. package/lib/stores/messageStore.d.ts.map +1 -0
  209. package/lib/stores/messageStore.js +137 -2
  210. package/lib/stores/notificationStore.d.ts +33 -0
  211. package/lib/stores/notificationStore.d.ts.map +1 -0
  212. package/lib/stores/notificationStore.js +55 -0
  213. package/lib/stores/permissionStore.d.ts +37 -0
  214. package/lib/stores/permissionStore.d.ts.map +1 -0
  215. package/lib/stores/permissionStore.js +117 -0
  216. package/lib/stores/personaStore.d.ts +26 -0
  217. package/lib/stores/personaStore.d.ts.map +1 -0
  218. package/lib/stores/personaStore.js +118 -0
  219. package/lib/stores/postStore.d.ts +2 -1
  220. package/lib/stores/postStore.d.ts.map +1 -0
  221. package/lib/stores/postStore.js +53 -2
  222. package/lib/stores/reactionStore.d.ts +1 -0
  223. package/lib/stores/reactionStore.d.ts.map +1 -0
  224. package/lib/stores/reactionStore.js +28 -2
  225. package/lib/stores/subscriptionStore.d.ts +41 -0
  226. package/lib/stores/subscriptionStore.d.ts.map +1 -0
  227. package/lib/stores/subscriptionStore.js +85 -0
  228. package/lib/stores/tagStore.d.ts +8 -5
  229. package/lib/stores/tagStore.d.ts.map +1 -0
  230. package/lib/stores/tagStore.js +87 -2
  231. package/lib/stores/translationStore.d.ts +42 -0
  232. package/lib/stores/translationStore.d.ts.map +1 -0
  233. package/lib/stores/translationStore.js +122 -0
  234. package/lib/stores/userStore.d.ts +5 -4
  235. package/lib/stores/userStore.d.ts.map +1 -0
  236. package/lib/stores/userStore.js +319 -2
  237. package/lib/stores/videoStore.d.ts +39 -0
  238. package/lib/stores/videoStore.d.ts.map +1 -0
  239. package/lib/stores/videoStore.js +132 -0
  240. package/lib/stores/websocketStore.d.ts +1 -0
  241. package/lib/stores/websocketStore.d.ts.map +1 -0
  242. package/lib/stores/websocketStore.js +51 -2
  243. package/lib/types/apps.types.d.ts +17 -0
  244. package/lib/types/apps.types.d.ts.map +1 -0
  245. package/lib/types/apps.types.js +6 -0
  246. package/lib/types/common.types.d.ts +31 -0
  247. package/lib/types/common.types.d.ts.map +1 -0
  248. package/lib/types/common.types.js +6 -0
  249. package/lib/types/conversations.types.d.ts +17 -0
  250. package/lib/types/conversations.types.d.ts.map +1 -0
  251. package/lib/types/conversations.types.js +6 -0
  252. package/lib/types/edges.types.d.ts +38 -0
  253. package/lib/types/edges.types.d.ts.map +1 -0
  254. package/lib/types/edges.types.js +6 -0
  255. package/lib/types/groups.types.d.ts +19 -0
  256. package/lib/types/groups.types.d.ts.map +1 -0
  257. package/lib/types/groups.types.js +6 -0
  258. package/lib/types/index.d.ts +12 -0
  259. package/lib/types/index.d.ts.map +1 -0
  260. package/lib/types/index.js +12 -0
  261. package/lib/types/subscriptions.types.d.ts +32 -0
  262. package/lib/types/subscriptions.types.d.ts.map +1 -0
  263. package/lib/types/subscriptions.types.js +6 -0
  264. package/lib/types/videos.types.d.ts +61 -0
  265. package/lib/types/videos.types.d.ts.map +1 -0
  266. package/lib/types/videos.types.js +6 -0
  267. package/lib/utils/MetropolisProvider.d.ts +39 -15
  268. package/lib/utils/MetropolisProvider.d.ts.map +1 -0
  269. package/lib/utils/MetropolisProvider.js +31 -2
  270. package/lib/utils/actionFactory.d.ts +21 -19
  271. package/lib/utils/actionFactory.d.ts.map +1 -0
  272. package/lib/utils/actionFactory.js +95 -2
  273. package/lib/utils/api.d.ts +5 -4
  274. package/lib/utils/api.d.ts.map +1 -0
  275. package/lib/utils/api.js +252 -6
  276. package/lib/utils/app.d.ts +1 -0
  277. package/lib/utils/app.d.ts.map +1 -0
  278. package/lib/utils/app.js +15 -2
  279. package/lib/utils/baseActionFactory.d.ts +5 -23
  280. package/lib/utils/baseActionFactory.d.ts.map +1 -0
  281. package/lib/utils/baseActionFactory.js +72 -2
  282. package/lib/utils/configUtils.d.ts +11 -0
  283. package/lib/utils/configUtils.d.ts.map +1 -0
  284. package/lib/utils/configUtils.js +20 -0
  285. package/lib/utils/dateUtils.d.ts +1 -0
  286. package/lib/utils/dateUtils.d.ts.map +1 -0
  287. package/lib/utils/dateUtils.js +11 -2
  288. package/lib/utils/file.d.ts +3 -1
  289. package/lib/utils/file.d.ts.map +1 -0
  290. package/lib/utils/file.js +156 -2
  291. package/lib/utils/i18n.d.ts +7 -0
  292. package/lib/utils/i18n.d.ts.map +1 -0
  293. package/lib/utils/i18n.js +96 -0
  294. package/lib/utils/index.d.ts +20 -0
  295. package/lib/utils/index.d.ts.map +1 -0
  296. package/lib/utils/index.js +26 -0
  297. package/lib/utils/location.d.ts +4 -3
  298. package/lib/utils/location.d.ts.map +1 -0
  299. package/lib/utils/location.js +82 -2
  300. package/lib/utils/permissionUtils.d.ts +22 -0
  301. package/lib/utils/permissionUtils.d.ts.map +1 -0
  302. package/lib/utils/permissionUtils.js +72 -0
  303. package/lib/utils/requestCache.d.ts +8 -0
  304. package/lib/utils/requestCache.d.ts.map +1 -0
  305. package/lib/utils/requestCache.js +53 -0
  306. package/lib/utils/session.d.ts +14 -0
  307. package/lib/utils/session.d.ts.map +1 -0
  308. package/lib/utils/session.js +107 -0
  309. package/lib/utils/useConversationTyping.d.ts +26 -0
  310. package/lib/utils/useConversationTyping.d.ts.map +1 -0
  311. package/lib/utils/useConversationTyping.js +117 -0
  312. package/lib/utils/useMetropolis.d.ts +67 -12
  313. package/lib/utils/useMetropolis.d.ts.map +1 -0
  314. package/lib/utils/useMetropolis.js +311 -2
  315. package/lib/utils/useTranslations.d.ts +16 -0
  316. package/lib/utils/useTranslations.d.ts.map +1 -0
  317. package/lib/utils/useTranslations.js +105 -0
  318. package/lib/utils/validatorFactory.d.ts +3 -2
  319. package/lib/utils/validatorFactory.d.ts.map +1 -0
  320. package/lib/utils/validatorFactory.js +95 -2
  321. package/package.json +58 -17
  322. package/temp_signin.ts +73 -0
  323. package/lib/actions/profileActions/profileActions.d.ts +0 -50
  324. package/lib/actions/profileActions/profileActions.js +0 -2
  325. package/lib/adapters/profileAdapter/profileAdapter.d.ts +0 -32
  326. package/lib/adapters/profileAdapter/profileAdapter.js +0 -2
  327. package/lib/stores/profileStore.d.ts +0 -24
  328. package/lib/stores/profileStore.js +0 -2
  329. /package/{FACTORY_PATTERN_GUIDE.md → factoryPatternGuide.md} +0 -0
@@ -0,0 +1,702 @@
1
+ # MetropolisJS CRUD Integration Guide
2
+
3
+ This guide covers CRUD (Create, Read, Update, Delete) operations in MetropolisJS, including state management with ArkhamJS, extensible fields, and best practices.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Overview](#overview)
8
+ - [Basic Concepts](#basic-concepts)
9
+ - [CRUD Operations](#crud-operations)
10
+ - [Extensible Fields](#extensible-fields)
11
+ - [State Management](#state-management)
12
+ - [Error Handling](#error-handling)
13
+ - [Best Practices](#best-practices)
14
+
15
+ ## Overview
16
+
17
+ MetropolisJS provides a unified interface for performing CRUD operations on all collection types. Each collection follows consistent patterns through factory-based actions, Zod validation, and ArkhamJS state management.
18
+
19
+ ### Available Collections
20
+
21
+ All collections are defined in `COLLECTIONS` constant:
22
+
23
+ ```typescript
24
+ import {COLLECTIONS} from '@nlabs/metropolisjs';
25
+
26
+ const {
27
+ APPS, // 'apps'
28
+ CONVERSATIONS, // 'conversations'
29
+ FILES, // 'files'
30
+ GROUPS, // 'groups'
31
+ IMAGES, // 'images'
32
+ MESSAGES, // 'messages'
33
+ POSTS, // 'posts'
34
+ PERSONAS, // 'personas'
35
+ TAGS, // 'tags'
36
+ USERS, // 'users'
37
+ VIDEOS // 'videos'
38
+ } = COLLECTIONS;
39
+ ```
40
+
41
+ ## Basic Concepts
42
+
43
+ ### Factory Pattern
44
+
45
+ All actions are created using factory functions:
46
+
47
+ ```typescript
48
+ import {Flux} from '@nlabs/arkhamjs';
49
+ import {createPostActions, createGroupActions, createUserActions} from '@nlabs/metropolisjs';
50
+
51
+ const flux = new Flux();
52
+
53
+ const postActions = createPostActions(flux);
54
+ const groupActions = createGroupActions(flux);
55
+ const userActions = createUserActions(flux);
56
+ ```
57
+
58
+ ### Action Interface
59
+
60
+ Most collections provide standard CRUD methods:
61
+
62
+ ```typescript
63
+ interface CollectionActions {
64
+ add: (data, props?) => Promise<Item>;
65
+ itemById: (id, props?) => Promise<Item>;
66
+ list: (filters?, props?) => Promise<Item[]>;
67
+ delete: (id, props?) => Promise<Item>;
68
+ update: (data, props?) => Promise<Item>;
69
+ updateAdapter: (adapter) => void;
70
+ updateAdapterOptions: (options) => void;
71
+ }
72
+ ```
73
+
74
+ ### Field Selection
75
+
76
+ All CRUD methods accept an optional `props` parameter to specify additional fields to retrieve:
77
+
78
+ ```typescript
79
+ const post = await postActions.itemById('post123', [
80
+ 'viewCount',
81
+ 'likeCount',
82
+ 'comments {commentId, content, user {username}}'
83
+ ]);
84
+ ```
85
+
86
+ ## CRUD Operations
87
+
88
+ ### Create (Add)
89
+
90
+ Add new items to a collection:
91
+
92
+ ```typescript
93
+ // Add a post
94
+ const newPost = await postActions.add({
95
+ name: 'My First Post',
96
+ content: 'Hello, World!',
97
+ type: 'text',
98
+ tags: [{name: 'introduction'}]
99
+ });
100
+
101
+ // Add a group
102
+ const newGroup = await groupActions.add({
103
+ name: 'My Group',
104
+ description: 'A group for discussion',
105
+ isPrivate: false,
106
+ type: 'community'
107
+ });
108
+
109
+ // Add with extensible fields
110
+ const postWithMetadata = await postActions.add({
111
+ name: 'Custom Post',
112
+ content: 'Post with metadata',
113
+ metadata: {
114
+ priority: 'high',
115
+ category: 'announcement'
116
+ }
117
+ });
118
+ ```
119
+
120
+ ### Read (Retrieve)
121
+
122
+ Retrieve items by ID or using list methods:
123
+
124
+ ```typescript
125
+ // Get single item by ID
126
+ const post = await postActions.itemById('post123', [
127
+ 'tags {name, tagId}',
128
+ 'user {username, imageUrl}'
129
+ ]);
130
+
131
+ // List items with pagination
132
+ const recentPosts = await postActions.listByLatest(0, 20);
133
+
134
+ // List by location
135
+ const nearbyPosts = await postActions.listByLocation(
136
+ 37.7749, // latitude
137
+ -122.4194, // longitude
138
+ 0, // from
139
+ 10 // to
140
+ );
141
+
142
+ // List by tags
143
+ const taggedPosts = await postActions.listByTags(
144
+ ['technology', 'news'],
145
+ 37.7749,
146
+ -122.4194,
147
+ 0,
148
+ 10
149
+ );
150
+
151
+ // List by reactions
152
+ const popularPosts = await postActions.listByReactions(
153
+ ['like', 'view'],
154
+ 37.7749,
155
+ -122.4194,
156
+ 0,
157
+ 10
158
+ );
159
+ ```
160
+
161
+ ### Update
162
+
163
+ Update existing items:
164
+
165
+ ```typescript
166
+ // Update post
167
+ const updatedPost = await postActions.update({
168
+ postId: 'post123',
169
+ content: 'Updated content',
170
+ name: 'Updated Title'
171
+ });
172
+
173
+ // Update group
174
+ const updatedGroup = await groupActions.update({
175
+ groupId: 'group456',
176
+ description: 'New description',
177
+ settings: {
178
+ allowInvites: true,
179
+ requireApproval: false
180
+ }
181
+ });
182
+
183
+ // Partial updates with extensible fields
184
+ const partialUpdate = await postActions.update({
185
+ postId: 'post123',
186
+ customField: 'new value'
187
+ });
188
+ ```
189
+
190
+ ### Delete
191
+
192
+ Remove items from collections:
193
+
194
+ ```typescript
195
+ // Delete post
196
+ const deletedPost = await postActions.delete('post123');
197
+
198
+ // Delete group
199
+ const deletedGroup = await groupActions.delete('group456');
200
+
201
+ // Delete returns the deleted item
202
+ console.log(`Deleted post: ${deletedPost.name}`);
203
+ ```
204
+
205
+ ## Extensible Fields
206
+
207
+ All collection types support extensible fields through the `ExtensibleFields` interface, allowing custom properties beyond the predefined schema.
208
+
209
+ ### Using Extensible Fields
210
+
211
+ ```typescript
212
+ // Add custom fields to posts
213
+ const post = await postActions.add({
214
+ name: 'Event Announcement',
215
+ content: 'Join us for the meetup',
216
+ eventDate: '2024-06-15',
217
+ eventLocation: 'San Francisco',
218
+ capacity: 50,
219
+ registrationUrl: 'https://example.com/register'
220
+ });
221
+
222
+ // Query with custom fields
223
+ const postWithCustomFields = await postActions.itemById('post123', [
224
+ 'eventDate',
225
+ 'eventLocation',
226
+ 'capacity'
227
+ ]);
228
+
229
+ // Update custom fields
230
+ await postActions.update({
231
+ postId: 'post123',
232
+ capacity: 75,
233
+ soldOut: true
234
+ });
235
+ ```
236
+
237
+ ### Common Use Cases
238
+
239
+ **1. Metadata Storage:**
240
+ ```typescript
241
+ const post = await postActions.add({
242
+ name: 'Article',
243
+ content: 'Content...',
244
+ metadata: {
245
+ author: 'John Doe',
246
+ category: 'Tech',
247
+ readTime: 5
248
+ }
249
+ });
250
+ ```
251
+
252
+ **2. Feature Flags:**
253
+ ```typescript
254
+ const group = await groupActions.add({
255
+ name: 'Beta Group',
256
+ description: 'Testing new features',
257
+ features: {
258
+ chatEnabled: true,
259
+ videoEnabled: false,
260
+ pollsEnabled: true
261
+ }
262
+ });
263
+ ```
264
+
265
+ **3. Custom Timestamps:**
266
+ ```typescript
267
+ const post = await postActions.add({
268
+ name: 'Scheduled Post',
269
+ content: 'Future content',
270
+ scheduledPublishDate: Date.now() + 86400000,
271
+ lastReviewedDate: Date.now()
272
+ });
273
+ ```
274
+
275
+ ## State Management
276
+
277
+ MetropolisJS uses ArkhamJS for state management, automatically dispatching actions on CRUD operations.
278
+
279
+ ### Store Structure
280
+
281
+ Each collection has its own store with consistent structure:
282
+
283
+ ```typescript
284
+ {
285
+ [collectionName]: {
286
+ item: {}, // Single item from get/add/update
287
+ list: [], // List of items from list queries
288
+ error: null, // Last error if any
289
+ loading: false // Loading state
290
+ }
291
+ }
292
+ ```
293
+
294
+ ### Accessing State
295
+
296
+ ```typescript
297
+ import {useFlux} from '@nlabs/arkhamjs-utils-react';
298
+
299
+ const MyComponent = () => {
300
+ const flux = useFlux();
301
+
302
+ // Get single post
303
+ const post = flux.getState('posts.item', {});
304
+
305
+ // Get list of posts
306
+ const postList = flux.getState('posts.list', []);
307
+
308
+ // Get error state
309
+ const error = flux.getState('posts.error', null);
310
+
311
+ // Access nested state
312
+ const user = flux.getState('users.item', {});
313
+
314
+ return (
315
+ <div>
316
+ {post.name && <h1>{post.name}</h1>}
317
+ {postList.map(p => <div key={p.postId}>{p.name}</div>)}
318
+ </div>
319
+ );
320
+ };
321
+ ```
322
+
323
+ ### Store Constants
324
+
325
+ Each collection defines action constants for state updates:
326
+
327
+ ```typescript
328
+ import {POST_CONSTANTS, GROUP_CONSTANTS} from '@nlabs/metropolisjs';
329
+
330
+ // Listen for specific actions
331
+ flux.on(POST_CONSTANTS.ADD_ITEM_SUCCESS, (state) => {
332
+ const newPost = state.posts.item;
333
+ console.log('Post created:', newPost);
334
+ });
335
+
336
+ flux.on(GROUP_CONSTANTS.GET_LIST_SUCCESS, (state) => {
337
+ const groups = state.groups.list;
338
+ console.log('Groups loaded:', groups.length);
339
+ });
340
+ ```
341
+
342
+ ### Manual State Updates
343
+
344
+ ```typescript
345
+ // Dispatch custom actions
346
+ flux.dispatch({
347
+ type: POST_CONSTANTS.ADD_ITEM_SUCCESS,
348
+ post: customPostData
349
+ });
350
+
351
+ // Clear state
352
+ flux.dispatch({
353
+ type: POST_CONSTANTS.GET_LIST_SUCCESS,
354
+ list: []
355
+ });
356
+ ```
357
+
358
+ ## Error Handling
359
+
360
+ ### Try-Catch Pattern
361
+
362
+ ```typescript
363
+ import {PostValidationError} from '@nlabs/metropolisjs';
364
+
365
+ try {
366
+ const post = await postActions.add({
367
+ name: 'New Post',
368
+ content: 'Content here'
369
+ });
370
+ console.log('Post created:', post.postId);
371
+ } catch (error) {
372
+ if (error instanceof PostValidationError) {
373
+ console.error('Validation error:', error.message);
374
+ console.error('Failed field:', error.field);
375
+ } else {
376
+ console.error('API error:', error);
377
+ }
378
+ }
379
+ ```
380
+
381
+ ### Error State
382
+
383
+ Errors are automatically stored in the state:
384
+
385
+ ```typescript
386
+ const MyComponent = () => {
387
+ const flux = useFlux();
388
+ const error = flux.getState('posts.error', null);
389
+
390
+ React.useEffect(() => {
391
+ if (error) {
392
+ console.error('Post operation failed:', error);
393
+ // Show error notification
394
+ }
395
+ }, [error]);
396
+
397
+ return <div>{error && <ErrorMessage error={error} />}</div>;
398
+ };
399
+ ```
400
+
401
+ ### Validation Errors
402
+
403
+ Collections use Zod schemas for validation:
404
+
405
+ ```typescript
406
+ try {
407
+ await postActions.add({
408
+ // Missing required fields or invalid data
409
+ content: null
410
+ });
411
+ } catch (error) {
412
+ // Error message includes field-level details
413
+ // "Post validation failed: content: Expected string, received null"
414
+ }
415
+ ```
416
+
417
+ ## Best Practices
418
+
419
+ ### 1. Use Factory Functions
420
+
421
+ Always create actions using factory functions:
422
+
423
+ ```typescript
424
+ // ✅ Correct
425
+ const postActions = createPostActions(flux);
426
+
427
+ // ❌ Incorrect - direct instantiation not supported
428
+ const postActions = new PostActions(flux);
429
+ ```
430
+
431
+ ### 2. Request Only Needed Fields
432
+
433
+ Minimize data transfer by requesting only required fields:
434
+
435
+ ```typescript
436
+ // ✅ Efficient
437
+ const posts = await postActions.listByLatest(0, 10, [
438
+ 'viewCount',
439
+ 'likeCount'
440
+ ]);
441
+
442
+ // ❌ Inefficient - retrieves all nested data
443
+ const posts = await postActions.listByLatest(0, 10, [
444
+ 'user {*}',
445
+ 'tags {*}',
446
+ 'comments {*}'
447
+ ]);
448
+ ```
449
+
450
+ ### 3. Handle Pagination
451
+
452
+ Always implement pagination for large datasets:
453
+
454
+ ```typescript
455
+ const PAGE_SIZE = 20;
456
+
457
+ const loadMore = async (page: number) => {
458
+ const from = page * PAGE_SIZE;
459
+ const to = from + PAGE_SIZE;
460
+ return await postActions.listByLatest(from, to);
461
+ };
462
+ ```
463
+
464
+ ### 4. Validate Before Submission
465
+
466
+ Pre-validate data before API calls:
467
+
468
+ ```typescript
469
+ import {validatePostInput} from '@nlabs/metropolisjs';
470
+
471
+ const handleSubmit = async (formData) => {
472
+ try {
473
+ // Validate locally first
474
+ const validatedData = validatePostInput(formData);
475
+
476
+ // Submit to API
477
+ const post = await postActions.add(validatedData);
478
+ } catch (error) {
479
+ // Handle validation errors before API call
480
+ showValidationErrors(error);
481
+ }
482
+ };
483
+ ```
484
+
485
+ ### 5. Use Custom Adapters for Business Logic
486
+
487
+ Implement custom validation or transformation:
488
+
489
+ ```typescript
490
+ const customPostAdapter = (input: unknown) => {
491
+ const post = validatePostInput(input);
492
+
493
+ // Add business logic
494
+ return {
495
+ ...post,
496
+ processedContent: sanitizeHtml(post.content),
497
+ contentPreview: post.content?.substring(0, 200)
498
+ };
499
+ };
500
+
501
+ const postActions = createPostActions(flux, {
502
+ postAdapter: customPostAdapter
503
+ });
504
+ ```
505
+
506
+ ### 6. Leverage Extensible Fields
507
+
508
+ Use extensible fields for application-specific data:
509
+
510
+ ```typescript
511
+ // Store application state
512
+ const post = await postActions.add({
513
+ name: 'Post',
514
+ content: 'Content',
515
+ // Custom fields for your app
516
+ isDraft: true,
517
+ publishDate: Date.now(),
518
+ analytics: {
519
+ impressions: 0,
520
+ clicks: 0
521
+ }
522
+ });
523
+ ```
524
+
525
+ ### 7. Clean Up State
526
+
527
+ Clear state when unmounting components:
528
+
529
+ ```typescript
530
+ React.useEffect(() => {
531
+ return () => {
532
+ // Clear post list on unmount
533
+ flux.dispatch({
534
+ type: POST_CONSTANTS.GET_LIST_SUCCESS,
535
+ list: []
536
+ });
537
+ };
538
+ }, []);
539
+ ```
540
+
541
+ ### 8. Batch Operations
542
+
543
+ Perform multiple operations efficiently:
544
+
545
+ ```typescript
546
+ const createPostsInGroup = async (groupId: string, postData: any[]) => {
547
+ const posts = await Promise.all(
548
+ postData.map(data => postActions.add({
549
+ ...data,
550
+ groupId
551
+ }))
552
+ );
553
+
554
+ // Connect all posts to group
555
+ await Promise.all(
556
+ posts.map(post => connectionActions.addConnection(
557
+ COLLECTIONS.POSTS,
558
+ post.postId,
559
+ COLLECTIONS.GROUPS,
560
+ groupId
561
+ ))
562
+ );
563
+
564
+ return posts;
565
+ };
566
+ ```
567
+
568
+ ### 9. Type Safety
569
+
570
+ Use TypeScript interfaces for type safety:
571
+
572
+ ```typescript
573
+ import type {PostType, GroupType} from '@nlabs/metropolisjs';
574
+
575
+ const processPost = (post: PostType): string => {
576
+ return `${post.name}: ${post.content}`;
577
+ };
578
+
579
+ const createGroupPost = async (
580
+ group: GroupType,
581
+ postData: Partial<PostType>
582
+ ): Promise<PostType> => {
583
+ return await postActions.add({
584
+ ...postData,
585
+ groupId: group.groupId
586
+ });
587
+ };
588
+ ```
589
+
590
+ ### 10. Error Recovery
591
+
592
+ Implement retry logic for failed operations:
593
+
594
+ ```typescript
595
+ const retryOperation = async <T>(
596
+ operation: () => Promise<T>,
597
+ maxRetries: number = 3
598
+ ): Promise<T> => {
599
+ for (let i = 0; i < maxRetries; i++) {
600
+ try {
601
+ return await operation();
602
+ } catch (error) {
603
+ if (i === maxRetries - 1) throw error;
604
+ await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
605
+ }
606
+ }
607
+ throw new Error('Max retries exceeded');
608
+ };
609
+
610
+ // Usage
611
+ const post = await retryOperation(() =>
612
+ postActions.itemById('post123')
613
+ );
614
+ ```
615
+
616
+ ## Examples by Collection
617
+
618
+ ### Posts
619
+
620
+ ```typescript
621
+ const postActions = createPostActions(flux);
622
+
623
+ // Create
624
+ const post = await postActions.add({
625
+ name: 'Post Title',
626
+ content: 'Post content',
627
+ type: 'text',
628
+ tags: [{name: 'tech'}]
629
+ });
630
+
631
+ // Read
632
+ const post = await postActions.itemById('post123');
633
+ const posts = await postActions.listByLatest(0, 10);
634
+
635
+ // Update
636
+ await postActions.update({
637
+ postId: 'post123',
638
+ content: 'Updated content'
639
+ });
640
+
641
+ // Delete
642
+ await postActions.delete('post123');
643
+ ```
644
+
645
+ ### Groups
646
+
647
+ ```typescript
648
+ const groupActions = createGroupActions(flux);
649
+
650
+ // Create
651
+ const group = await groupActions.add({
652
+ name: 'Tech Group',
653
+ description: 'Discuss technology',
654
+ isPrivate: false
655
+ });
656
+
657
+ // Read
658
+ const group = await groupActions.itemById('group123');
659
+ const groups = await groupActions.listByLatest(0, 10);
660
+
661
+ // Update
662
+ await groupActions.update({
663
+ groupId: 'group123',
664
+ settings: {allowInvites: true}
665
+ });
666
+
667
+ // Delete
668
+ await groupActions.delete('group123');
669
+ ```
670
+
671
+ ### Content
672
+
673
+ ```typescript
674
+ const contentActions = createContentActions(flux);
675
+
676
+ // Create
677
+ const content = await contentActions.add({
678
+ key: 'welcome_message',
679
+ locale: 'en',
680
+ content: 'Welcome to our app!',
681
+ category: 'onboarding'
682
+ });
683
+
684
+ // Read
685
+ const content = await contentActions.itemByKey('welcome_message', 'en');
686
+ const contents = await contentActions.listByCategory('onboarding');
687
+
688
+ // Update
689
+ await contentActions.update({
690
+ contentId: 'content123',
691
+ content: 'Updated welcome message'
692
+ });
693
+
694
+ // Delete
695
+ await contentActions.delete('content123');
696
+ ```
697
+
698
+ ## Next Steps
699
+
700
+ - [Collections Reference](./COLLECTIONS.md) - Detailed field information for each collection
701
+ - [Connections Guide](./CONNECTIONS.md) - Managing relationships between collections
702
+ - [MetropolisJS Documentation](../README.md) - Main library documentation