@nlabs/metropolisjs 0.1.1 → 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 (326) 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 +1343 -0
  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/factory-pattern-usage.ts +283 -0
  19. package/examples/i18n-import-examples.ts +86 -0
  20. package/examples/i18n-namespace-usage.ts +118 -0
  21. package/examples/i18next-singleton-demo.ts +187 -0
  22. package/examples/permission-system-usage.tsx +415 -0
  23. package/examples/project-details.tsx +397 -0
  24. package/examples/shared-i18n-usage.tsx +203 -0
  25. package/examples/signup-error-handling.ts +100 -0
  26. package/examples/translation-types.ts +86 -0
  27. package/examples/translation-usage.tsx +336 -0
  28. package/factoryPatternGuide.md +244 -0
  29. package/index.js +1 -0
  30. package/jest.config.mjs +28 -0
  31. package/lex.config.mjs +26 -0
  32. package/lib/__tests__/e2e/helpers/testGraphQLServer.d.ts +22 -0
  33. package/lib/__tests__/e2e/helpers/testGraphQLServer.d.ts.map +1 -0
  34. package/lib/__tests__/e2e/helpers/testGraphQLServer.js +197 -0
  35. package/lib/__tests__/e2e/helpers/testGraphQLServerSimple.d.ts +3 -0
  36. package/lib/__tests__/e2e/helpers/testGraphQLServerSimple.d.ts.map +1 -0
  37. package/lib/__tests__/e2e/helpers/testGraphQLServerSimple.js +52 -0
  38. package/lib/actions/appActions/appActions.d.ts +29 -0
  39. package/lib/actions/appActions/appActions.d.ts.map +1 -0
  40. package/lib/actions/appActions/appActions.js +159 -0
  41. package/lib/actions/connectionActions/connectionActions.d.ts +19 -0
  42. package/lib/actions/connectionActions/connectionActions.d.ts.map +1 -0
  43. package/lib/actions/connectionActions/connectionActions.js +131 -0
  44. package/lib/actions/contentActions/contentActions.d.ts +34 -0
  45. package/lib/actions/contentActions/contentActions.d.ts.map +1 -0
  46. package/lib/actions/contentActions/contentActions.js +314 -0
  47. package/lib/actions/conversationActions/conversationActions.d.ts +30 -0
  48. package/lib/actions/conversationActions/conversationActions.d.ts.map +1 -0
  49. package/lib/actions/conversationActions/conversationActions.js +225 -0
  50. package/lib/actions/eventActions/eventActions.d.ts +65 -0
  51. package/lib/actions/eventActions/eventActions.d.ts.map +1 -0
  52. package/lib/actions/eventActions/eventActions.js +436 -0
  53. package/lib/actions/groupActions/groupActions.d.ts +30 -0
  54. package/lib/actions/groupActions/groupActions.d.ts.map +1 -0
  55. package/lib/actions/groupActions/groupActions.js +229 -0
  56. package/lib/actions/imageActions/imageActions.d.ts +62 -0
  57. package/lib/actions/imageActions/imageActions.d.ts.map +1 -0
  58. package/lib/actions/imageActions/imageActions.js +593 -0
  59. package/lib/actions/index.d.ts +21 -0
  60. package/lib/actions/index.d.ts.map +1 -0
  61. package/lib/actions/index.js +22 -0
  62. package/lib/actions/locationActions/locationActions.d.ts +60 -0
  63. package/lib/actions/locationActions/locationActions.d.ts.map +1 -0
  64. package/lib/actions/locationActions/locationActions.js +388 -0
  65. package/lib/actions/messageActions/messageActions.d.ts +38 -0
  66. package/lib/actions/messageActions/messageActions.d.ts.map +1 -0
  67. package/lib/actions/messageActions/messageActions.js +235 -0
  68. package/lib/actions/permissionActions/permissionActions.d.ts +34 -0
  69. package/lib/actions/permissionActions/permissionActions.d.ts.map +1 -0
  70. package/lib/actions/permissionActions/permissionActions.js +330 -0
  71. package/lib/actions/personaActions/personaActions.d.ts +65 -0
  72. package/lib/actions/personaActions/personaActions.d.ts.map +1 -0
  73. package/lib/actions/personaActions/personaActions.js +572 -0
  74. package/lib/actions/postActions/postActions.d.ts +36 -0
  75. package/lib/actions/postActions/postActions.d.ts.map +1 -0
  76. package/lib/actions/postActions/postActions.js +447 -0
  77. package/lib/actions/reactionActions/reactionActions.d.ts +38 -0
  78. package/lib/actions/reactionActions/reactionActions.d.ts.map +1 -0
  79. package/lib/actions/reactionActions/reactionActions.js +413 -0
  80. package/lib/actions/sseActions/sseActions.d.ts +38 -0
  81. package/lib/actions/sseActions/sseActions.d.ts.map +1 -0
  82. package/lib/actions/sseActions/sseActions.js +148 -0
  83. package/lib/actions/subscriptionActions/subscriptionActions.d.ts +24 -0
  84. package/lib/actions/subscriptionActions/subscriptionActions.d.ts.map +1 -0
  85. package/lib/actions/subscriptionActions/subscriptionActions.js +329 -0
  86. package/lib/actions/tagActions/tagActions.d.ts +37 -0
  87. package/lib/actions/tagActions/tagActions.d.ts.map +1 -0
  88. package/lib/actions/tagActions/tagActions.js +347 -0
  89. package/lib/actions/translationActions/translationActions.d.ts +38 -0
  90. package/lib/actions/translationActions/translationActions.d.ts.map +1 -0
  91. package/lib/actions/translationActions/translationActions.js +189 -0
  92. package/lib/actions/userActions/userActions.d.ts +78 -0
  93. package/lib/actions/userActions/userActions.d.ts.map +1 -0
  94. package/lib/actions/userActions/userActions.js +844 -0
  95. package/lib/actions/videoActions/videoActions.d.ts +41 -0
  96. package/lib/actions/videoActions/videoActions.d.ts.map +1 -0
  97. package/lib/actions/videoActions/videoActions.js +532 -0
  98. package/lib/actions/websocketActions/websocketActions.d.ts +30 -0
  99. package/lib/actions/websocketActions/websocketActions.d.ts.map +1 -0
  100. package/lib/actions/websocketActions/websocketActions.js +377 -0
  101. package/lib/adapters/appAdapter/appAdapter.d.ts +8 -0
  102. package/lib/adapters/appAdapter/appAdapter.d.ts.map +1 -0
  103. package/lib/adapters/appAdapter/appAdapter.js +90 -0
  104. package/lib/adapters/arangoAdapter/arangoAdapter.d.ts +21 -0
  105. package/lib/adapters/arangoAdapter/arangoAdapter.d.ts.map +1 -0
  106. package/lib/adapters/arangoAdapter/arangoAdapter.js +75 -0
  107. package/lib/adapters/contentAdapter/contentAdapter.d.ts +32 -0
  108. package/lib/adapters/contentAdapter/contentAdapter.d.ts.map +1 -0
  109. package/lib/adapters/contentAdapter/contentAdapter.js +107 -0
  110. package/lib/adapters/conversationAdapter/conversationAdapter.d.ts +24 -0
  111. package/lib/adapters/conversationAdapter/conversationAdapter.d.ts.map +1 -0
  112. package/lib/adapters/conversationAdapter/conversationAdapter.js +75 -0
  113. package/lib/adapters/eventAdapter/eventAdapter.d.ts +46 -0
  114. package/lib/adapters/eventAdapter/eventAdapter.d.ts.map +1 -0
  115. package/lib/adapters/eventAdapter/eventAdapter.js +162 -0
  116. package/lib/adapters/fileAdapter/fileAdapter.d.ts +30 -0
  117. package/lib/adapters/fileAdapter/fileAdapter.d.ts.map +1 -0
  118. package/lib/adapters/fileAdapter/fileAdapter.js +118 -0
  119. package/lib/adapters/groupAdapter/groupAdapter.d.ts +28 -0
  120. package/lib/adapters/groupAdapter/groupAdapter.d.ts.map +1 -0
  121. package/lib/adapters/groupAdapter/groupAdapter.js +66 -0
  122. package/lib/adapters/imageAdapter/imageAdapter.d.ts +38 -0
  123. package/lib/adapters/imageAdapter/imageAdapter.d.ts.map +1 -0
  124. package/lib/adapters/imageAdapter/imageAdapter.js +134 -0
  125. package/lib/adapters/index.d.ts +34 -0
  126. package/lib/adapters/index.d.ts.map +1 -0
  127. package/lib/adapters/index.js +19 -0
  128. package/lib/adapters/locationAdapter/locationAdapter.d.ts +28 -0
  129. package/lib/adapters/locationAdapter/locationAdapter.d.ts.map +1 -0
  130. package/lib/adapters/locationAdapter/locationAdapter.js +95 -0
  131. package/lib/adapters/messageAdapter/messageAdapter.d.ts +31 -0
  132. package/lib/adapters/messageAdapter/messageAdapter.d.ts.map +1 -0
  133. package/lib/adapters/messageAdapter/messageAdapter.js +82 -0
  134. package/lib/adapters/permissionAdapter/permissionAdapter.d.ts +41 -0
  135. package/lib/adapters/permissionAdapter/permissionAdapter.d.ts.map +1 -0
  136. package/lib/adapters/permissionAdapter/permissionAdapter.js +120 -0
  137. package/lib/adapters/personaAdapter/personaAdapter.d.ts +44 -0
  138. package/lib/adapters/personaAdapter/personaAdapter.d.ts.map +1 -0
  139. package/lib/adapters/personaAdapter/personaAdapter.js +161 -0
  140. package/lib/adapters/postAdapter/postAdapter.d.ts +33 -0
  141. package/lib/adapters/postAdapter/postAdapter.d.ts.map +1 -0
  142. package/lib/adapters/postAdapter/postAdapter.js +115 -0
  143. package/lib/adapters/reactionAdapter/reactionAdapter.d.ts +23 -0
  144. package/lib/adapters/reactionAdapter/reactionAdapter.d.ts.map +1 -0
  145. package/lib/adapters/reactionAdapter/reactionAdapter.js +81 -0
  146. package/lib/adapters/reaktorAdapter/reaktorAdapter.d.ts +17 -0
  147. package/lib/adapters/reaktorAdapter/reaktorAdapter.d.ts.map +1 -0
  148. package/lib/adapters/reaktorAdapter/reaktorAdapter.js +58 -0
  149. package/lib/adapters/sessionAdapter/sessionAdapter.d.ts +24 -0
  150. package/lib/adapters/sessionAdapter/sessionAdapter.d.ts.map +1 -0
  151. package/lib/adapters/sessionAdapter/sessionAdapter.js +80 -0
  152. package/lib/adapters/tagAdapter/tagAdapter.d.ts +21 -0
  153. package/lib/adapters/tagAdapter/tagAdapter.d.ts.map +1 -0
  154. package/lib/adapters/tagAdapter/tagAdapter.js +98 -0
  155. package/lib/adapters/translationAdapter/translationAdapter.d.ts +21 -0
  156. package/lib/adapters/translationAdapter/translationAdapter.d.ts.map +1 -0
  157. package/lib/adapters/translationAdapter/translationAdapter.js +55 -0
  158. package/lib/adapters/userAdapter/userAdapter.d.ts +67 -0
  159. package/lib/adapters/userAdapter/userAdapter.d.ts.map +1 -0
  160. package/lib/adapters/userAdapter/userAdapter.js +302 -0
  161. package/lib/adapters/videoAdapter/videoAdapter.d.ts +8 -0
  162. package/lib/adapters/videoAdapter/videoAdapter.d.ts.map +1 -0
  163. package/lib/adapters/videoAdapter/videoAdapter.js +194 -0
  164. package/lib/config/index.d.ts +44 -0
  165. package/lib/config/index.d.ts.map +1 -0
  166. package/lib/config/index.js +97 -0
  167. package/lib/constants/Collections.d.ts +44 -0
  168. package/lib/constants/Collections.d.ts.map +1 -0
  169. package/lib/constants/Collections.js +40 -0
  170. package/lib/constants/MetropolisConstants.d.ts +15 -0
  171. package/lib/constants/MetropolisConstants.d.ts.map +1 -0
  172. package/lib/constants/MetropolisConstants.js +15 -0
  173. package/lib/graphql/message.d.ts +3 -0
  174. package/lib/graphql/message.d.ts.map +1 -0
  175. package/lib/graphql/message.js +20 -0
  176. package/lib/graphql/notification.d.ts +3 -0
  177. package/lib/graphql/notification.d.ts.map +1 -0
  178. package/lib/graphql/notification.js +20 -0
  179. package/lib/graphql/session.d.ts +2 -0
  180. package/lib/graphql/session.d.ts.map +1 -0
  181. package/lib/graphql/session.js +17 -0
  182. package/lib/index.d.ts +52 -0
  183. package/lib/index.d.ts.map +1 -0
  184. package/lib/index.js +248 -0
  185. package/lib/stores/appStore.d.ts +23 -0
  186. package/lib/stores/appStore.d.ts.map +1 -0
  187. package/lib/stores/appStore.js +23 -0
  188. package/lib/stores/contentStore.d.ts +36 -0
  189. package/lib/stores/contentStore.d.ts.map +1 -0
  190. package/lib/stores/contentStore.js +139 -0
  191. package/lib/stores/conversationStore.d.ts +38 -0
  192. package/lib/stores/conversationStore.d.ts.map +1 -0
  193. package/lib/stores/conversationStore.js +117 -0
  194. package/lib/stores/eventStore.d.ts +37 -0
  195. package/lib/stores/eventStore.d.ts.map +1 -0
  196. package/lib/stores/eventStore.js +47 -0
  197. package/lib/stores/groupStore.d.ts +37 -0
  198. package/lib/stores/groupStore.d.ts.map +1 -0
  199. package/lib/stores/groupStore.js +68 -0
  200. package/lib/stores/imageStore.d.ts +40 -0
  201. package/lib/stores/imageStore.d.ts.map +1 -0
  202. package/lib/stores/imageStore.js +53 -0
  203. package/lib/stores/index.d.ts +24 -0
  204. package/lib/stores/index.d.ts.map +1 -0
  205. package/lib/stores/index.js +24 -0
  206. package/lib/stores/locationStore.d.ts +34 -0
  207. package/lib/stores/locationStore.d.ts.map +1 -0
  208. package/lib/stores/locationStore.js +42 -0
  209. package/lib/stores/messageStore.d.ts +51 -0
  210. package/lib/stores/messageStore.d.ts.map +1 -0
  211. package/lib/stores/messageStore.js +137 -0
  212. package/lib/stores/notificationStore.d.ts +33 -0
  213. package/lib/stores/notificationStore.d.ts.map +1 -0
  214. package/lib/stores/notificationStore.js +55 -0
  215. package/lib/stores/permissionStore.d.ts +37 -0
  216. package/lib/stores/permissionStore.d.ts.map +1 -0
  217. package/lib/stores/permissionStore.js +117 -0
  218. package/lib/stores/personaStore.d.ts +26 -0
  219. package/lib/stores/personaStore.d.ts.map +1 -0
  220. package/lib/stores/personaStore.js +118 -0
  221. package/lib/stores/postStore.d.ts +34 -0
  222. package/lib/stores/postStore.d.ts.map +1 -0
  223. package/lib/stores/postStore.js +53 -0
  224. package/lib/stores/reactionStore.d.ts +25 -0
  225. package/lib/stores/reactionStore.d.ts.map +1 -0
  226. package/lib/stores/reactionStore.js +28 -0
  227. package/lib/stores/subscriptionStore.d.ts +41 -0
  228. package/lib/stores/subscriptionStore.d.ts.map +1 -0
  229. package/lib/stores/subscriptionStore.js +85 -0
  230. package/lib/stores/tagStore.d.ts +34 -0
  231. package/lib/stores/tagStore.d.ts.map +1 -0
  232. package/lib/stores/tagStore.js +87 -0
  233. package/lib/stores/translationStore.d.ts +42 -0
  234. package/lib/stores/translationStore.d.ts.map +1 -0
  235. package/lib/stores/translationStore.js +122 -0
  236. package/lib/stores/userStore.d.ts +74 -0
  237. package/lib/stores/userStore.d.ts.map +1 -0
  238. package/lib/stores/userStore.js +319 -0
  239. package/lib/stores/videoStore.d.ts +39 -0
  240. package/lib/stores/videoStore.d.ts.map +1 -0
  241. package/lib/stores/videoStore.js +132 -0
  242. package/lib/stores/websocketStore.d.ts +24 -0
  243. package/lib/stores/websocketStore.d.ts.map +1 -0
  244. package/lib/stores/websocketStore.js +51 -0
  245. package/lib/types/apps.types.d.ts +17 -0
  246. package/lib/types/apps.types.d.ts.map +1 -0
  247. package/lib/types/apps.types.js +6 -0
  248. package/lib/types/common.types.d.ts +31 -0
  249. package/lib/types/common.types.d.ts.map +1 -0
  250. package/lib/types/common.types.js +6 -0
  251. package/lib/types/conversations.types.d.ts +17 -0
  252. package/lib/types/conversations.types.d.ts.map +1 -0
  253. package/lib/types/conversations.types.js +6 -0
  254. package/lib/types/edges.types.d.ts +38 -0
  255. package/lib/types/edges.types.d.ts.map +1 -0
  256. package/lib/types/edges.types.js +6 -0
  257. package/lib/types/groups.types.d.ts +19 -0
  258. package/lib/types/groups.types.d.ts.map +1 -0
  259. package/lib/types/groups.types.js +6 -0
  260. package/lib/types/index.d.ts +12 -0
  261. package/lib/types/index.d.ts.map +1 -0
  262. package/lib/types/index.js +12 -0
  263. package/lib/types/subscriptions.types.d.ts +32 -0
  264. package/lib/types/subscriptions.types.d.ts.map +1 -0
  265. package/lib/types/subscriptions.types.js +6 -0
  266. package/lib/types/videos.types.d.ts +61 -0
  267. package/lib/types/videos.types.d.ts.map +1 -0
  268. package/lib/types/videos.types.js +6 -0
  269. package/lib/utils/MetropolisProvider.d.ts +58 -0
  270. package/lib/utils/MetropolisProvider.d.ts.map +1 -0
  271. package/lib/utils/MetropolisProvider.js +31 -0
  272. package/lib/utils/actionFactory.d.ts +24 -0
  273. package/lib/utils/actionFactory.d.ts.map +1 -0
  274. package/lib/utils/actionFactory.js +95 -0
  275. package/lib/utils/api.d.ts +44 -0
  276. package/lib/utils/api.d.ts.map +1 -0
  277. package/lib/utils/api.js +253 -0
  278. package/lib/utils/app.d.ts +7 -0
  279. package/lib/utils/app.d.ts.map +1 -0
  280. package/lib/utils/app.js +15 -0
  281. package/lib/utils/baseActionFactory.d.ts +16 -0
  282. package/lib/utils/baseActionFactory.d.ts.map +1 -0
  283. package/lib/utils/baseActionFactory.js +72 -0
  284. package/lib/utils/configUtils.d.ts +11 -0
  285. package/lib/utils/configUtils.d.ts.map +1 -0
  286. package/lib/utils/configUtils.js +20 -0
  287. package/lib/utils/dateUtils.d.ts +3 -0
  288. package/lib/utils/dateUtils.d.ts.map +1 -0
  289. package/lib/utils/dateUtils.js +11 -0
  290. package/lib/utils/file.d.ts +3 -0
  291. package/lib/utils/file.d.ts.map +1 -0
  292. package/lib/utils/file.js +156 -0
  293. package/lib/utils/i18n.d.ts +7 -0
  294. package/lib/utils/i18n.d.ts.map +1 -0
  295. package/lib/utils/i18n.js +96 -0
  296. package/lib/utils/index.d.ts +20 -0
  297. package/lib/utils/index.d.ts.map +1 -0
  298. package/lib/utils/index.js +26 -0
  299. package/lib/utils/location.d.ts +10 -0
  300. package/lib/utils/location.d.ts.map +1 -0
  301. package/lib/utils/location.js +82 -0
  302. package/lib/utils/permissionUtils.d.ts +22 -0
  303. package/lib/utils/permissionUtils.d.ts.map +1 -0
  304. package/lib/utils/permissionUtils.js +72 -0
  305. package/lib/utils/requestCache.d.ts +8 -0
  306. package/lib/utils/requestCache.d.ts.map +1 -0
  307. package/lib/utils/requestCache.js +53 -0
  308. package/lib/utils/session.d.ts +14 -0
  309. package/lib/utils/session.d.ts.map +1 -0
  310. package/lib/utils/session.js +107 -0
  311. package/lib/utils/useConversationTyping.d.ts +26 -0
  312. package/lib/utils/useConversationTyping.d.ts.map +1 -0
  313. package/lib/utils/useConversationTyping.js +117 -0
  314. package/lib/utils/useMetropolis.d.ts +67 -0
  315. package/lib/utils/useMetropolis.d.ts.map +1 -0
  316. package/lib/utils/useMetropolis.js +311 -0
  317. package/lib/utils/useTranslations.d.ts +16 -0
  318. package/lib/utils/useTranslations.d.ts.map +1 -0
  319. package/lib/utils/useTranslations.js +105 -0
  320. package/lib/utils/validatorFactory.d.ts +49 -0
  321. package/lib/utils/validatorFactory.d.ts.map +1 -0
  322. package/lib/utils/validatorFactory.js +95 -0
  323. package/package.json +75 -28
  324. package/temp_signin.ts +73 -0
  325. package/tsconfig.lint.json +25 -0
  326. package/tsconfig.test.json +14 -0
package/README.md ADDED
@@ -0,0 +1,1343 @@
1
+ # MetropolisJS: Seamless Frontend-Backend Integration Framework
2
+
3
+ > **The Ultimate Frontend Integration Library for Modern Web Applications**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@nlabs/metropolisjs.svg?style=flat-square)](https://www.npmjs.com/package/@nlabs/metropolisjs)
6
+ [![npm downloads](https://img.shields.io/npm/dm/@nlabs/metropolisjs.svg?style=flat-square)](https://www.npmjs.com/package/@nlabs/metropolisjs)
7
+ [![Issues](http://img.shields.io/github/issues/nitrogenlabs/metropolisjs.svg?style=flat-square)](https://github.com/nitrogenlabs/metropolisjs/issues)
8
+ [![TypeScript](https://badges.frapsoft.com/typescript/version/typescript-next.svg?v=101)](https://github.com/ellerbrock/typescript-badges/)
9
+ [![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](http://opensource.org/licenses/MIT)
10
+ [![Chat](https://img.shields.io/discord/446122412715802649.svg)](https://discord.gg/Ttgev58)
11
+
12
+ MetropolisJS is the bridge that connects your frontend dreams to backend reality. Built on the powerful combination of **Reaktor** (backend services) and **ArkhamJS** (frontend data store), MetropolisJS provides a seamless, real-time integration layer that handles everything from user authentication to real-time messaging and notifications.
13
+
14
+ ## Why MetropolisJS?
15
+
16
+ ### **Seamless Integration**
17
+
18
+ Connect your React frontend to Reaktor-powered backend services with zero configuration headaches. MetropolisJS handles all the complex data flow, state management, and real-time communication.
19
+
20
+ ### **Real-Time Everything**
21
+
22
+ Built-in WebSocket and Server-Sent Events (SSE) support for instant messaging, live notifications, and real-time data synchronization. Your users will never miss a beat.
23
+
24
+ ### **Type-Safe & Reliable**
25
+
26
+ Full TypeScript support with comprehensive type definitions. Catch errors at compile time, not runtime.
27
+
28
+ ### **Developer Experience First**
29
+
30
+ Clean, intuitive APIs that make complex operations feel simple. Focus on building features, not boilerplate.
31
+
32
+ ## What Can You Build?
33
+ MetropolisJS powers applications that need:
34
+
35
+ - **User Authentication & Authorization**
36
+ - **Role-Based Access Control (RBAC)** with 5-level permission system
37
+ - **Real-Time Messaging Systems**
38
+ - **Live Notifications**
39
+ - **Social Media Features** (posts, reactions, tags)
40
+ - **Location-Based Services**
41
+ - **Media Management** (images, files)
42
+ - **Event Management**
43
+ - **User Connections & Relationships**
44
+
45
+ ## Quick Start
46
+
47
+ ### Installation
48
+
49
+ ```bash
50
+ npm install @nlabs/metropolisjs @nlabs/arkhamjs @nlabs/arkhamjs-utils-react
51
+ ```
52
+
53
+ ### Basic Setup
54
+
55
+ ```tsx
56
+ import {Metropolis, useUserActions, useMessageActions, useWebsocketActions} from '@nlabs/metropolisjs';
57
+
58
+ const App = () => {
59
+ return (
60
+ <Metropolis config={{
61
+ development: {
62
+ environment: 'development',
63
+ app: {
64
+ api: {
65
+ url: 'http://localhost:3000/app',
66
+ public: 'http://localhost:3000/public'
67
+ }
68
+ }
69
+ }
70
+ }}>
71
+ <YourApp />
72
+ </Metropolis>
73
+ );
74
+ };
75
+
76
+ const YourApp = () => {
77
+ // Use specialized hooks for better performance
78
+ const userActions = useUserActions();
79
+ const messageActions = useMessageActions();
80
+ const websocketActions = useWebsocketActions();
81
+
82
+ // Start building amazing features!
83
+ return <div>Your app content</div>;
84
+ };
85
+ ```
86
+
87
+ ### Using Actions
88
+
89
+ MetropolisJS provides multiple ways to access actions:
90
+
91
+ ```tsx
92
+ // Option 1: Specialized hooks (recommended - best performance)
93
+ const userActions = useUserActions();
94
+ const postActions = usePostActions();
95
+
96
+ // Option 2: Selective creation
97
+ const {userActions, postActions} = useMetropolis(['user', 'post']);
98
+
99
+ // Option 3: All actions (default behavior)
100
+ const {userActions, postActions, messageActions} = useMetropolis();
101
+ ```
102
+
103
+ ## Configuration
104
+
105
+ The `Metropolis` component accepts three main props: `config`, `adapters`, and `translations`. Here's how to configure each:
106
+
107
+ ### Configuration Object
108
+
109
+ The `config` prop accepts a `MetropolisConfiguration` object that supports environment-specific settings:
110
+
111
+ ```tsx
112
+ <Metropolis
113
+ config={{
114
+ // Environment-specific configurations
115
+ development: {
116
+ environment: 'development',
117
+ app: {
118
+ api: {
119
+ url: 'http://localhost:3000/app',
120
+ public: 'http://localhost:3000/public',
121
+ uploadImage: 'http://localhost:3000/upload'
122
+ },
123
+ urls: {
124
+ websocket: 'ws://localhost:3000'
125
+ },
126
+ session: {
127
+ maxMinutes: 1440, // 24 hours
128
+ minMinutes: 15
129
+ },
130
+ name: 'My App',
131
+ version: '1.0.0'
132
+ },
133
+ isAuth: () => {
134
+ // Custom authentication check
135
+ const session = flux.getState('user.session', {});
136
+ return !!session.userActive;
137
+ }
138
+ },
139
+ production: {
140
+ environment: 'production',
141
+ app: {
142
+ api: {
143
+ url: 'https://api.example.com/app',
144
+ public: 'https://api.example.com/public',
145
+ uploadImage: 'https://api.example.com/upload'
146
+ },
147
+ urls: {
148
+ websocket: 'wss://api.example.com'
149
+ },
150
+ session: {
151
+ maxMinutes: 2880, // 48 hours
152
+ minMinutes: 30
153
+ }
154
+ }
155
+ }
156
+ }}
157
+ >
158
+ <YourApp />
159
+ </Metropolis>
160
+ ```
161
+
162
+ #### Configuration Options
163
+
164
+ **Environment Configuration** (`MetropolisEnvironmentConfiguration`):
165
+ - `environment`: `'development' | 'production' | 'test' | 'local'` - Current environment
166
+ - `app`: Application-specific configuration
167
+ - `api`: API endpoint configuration
168
+ - `url`: Main API endpoint
169
+ - `public`: Public API endpoint
170
+ - `uploadImage`: Image upload endpoint
171
+ - `urls`: Additional URL configurations
172
+ - `websocket`: WebSocket server URL
173
+ - `session`: Session management settings
174
+ - `maxMinutes`: Maximum session duration in minutes
175
+ - `minMinutes`: Minimum session duration in minutes
176
+ - `name`: Application name
177
+ - `version`: Application version
178
+ - `isAuth`: Function that returns a boolean indicating if the user is authenticated
179
+ - `adapters`: Custom adapters (can also be passed as a separate prop)
180
+
181
+ ### Custom Adapters
182
+
183
+ Pass custom adapters to override default data transformation behavior:
184
+
185
+ ```tsx
186
+ import {parseUser, parseMessage} from '@nlabs/metropolisjs';
187
+
188
+ <Metropolis
189
+ adapters={{
190
+ User: parseUser,
191
+ Message: parseMessage,
192
+ // Add other custom adapters as needed
193
+ Content: customContentAdapter,
194
+ Event: customEventAdapter,
195
+ Image: customImageAdapter,
196
+ Location: customLocationAdapter,
197
+ Post: customPostAdapter,
198
+ Persona: customPersonaAdapter,
199
+ Reaction: customReactionAdapter,
200
+ Tag: customTagAdapter,
201
+ Translation: customTranslationAdapter
202
+ }}
203
+ >
204
+ <YourApp />
205
+ </Metropolis>
206
+ ```
207
+
208
+ ### Translations
209
+
210
+ MetropolisJS supports both simple and complex translation formats:
211
+
212
+ #### Simple Translations
213
+
214
+ ```tsx
215
+ <Metropolis
216
+ translations={{
217
+ 'welcome': 'Welcome to MetropolisJS!',
218
+ 'save': 'Save',
219
+ 'cancel': 'Cancel',
220
+ 'hello_user': 'Hello {{name}}!',
221
+ 'items_count': 'You have {{count}} items'
222
+ }}
223
+ >
224
+ <YourApp />
225
+ </Metropolis>
226
+ ```
227
+
228
+ #### Complex Translations (with locale and namespace)
229
+
230
+ ```tsx
231
+ <Metropolis
232
+ translations={{
233
+ 'welcome': {
234
+ value: 'Welcome to MetropolisJS!',
235
+ locale: 'en',
236
+ namespace: 'common'
237
+ },
238
+ 'save': {
239
+ value: 'Save',
240
+ locale: 'en',
241
+ namespace: 'actions'
242
+ }
243
+ }}
244
+ >
245
+ <YourApp />
246
+ </Metropolis>
247
+ ```
248
+
249
+ ### Complete Configuration Example
250
+
251
+ ```tsx
252
+ import {Metropolis} from '@nlabs/metropolisjs';
253
+ import {parseUser, parseMessage} from '@nlabs/metropolisjs';
254
+
255
+ const App = () => {
256
+ return (
257
+ <Metropolis
258
+ config={{
259
+ development: {
260
+ environment: 'development',
261
+ app: {
262
+ api: {
263
+ url: 'http://localhost:3000/app',
264
+ public: 'http://localhost:3000/public'
265
+ },
266
+ urls: {
267
+ websocket: 'ws://localhost:3000'
268
+ },
269
+ session: {
270
+ maxMinutes: 1440,
271
+ minMinutes: 15
272
+ }
273
+ },
274
+ isAuth: () => {
275
+ // Your custom auth logic
276
+ return true;
277
+ }
278
+ },
279
+ production: {
280
+ environment: 'production',
281
+ app: {
282
+ api: {
283
+ url: 'https://api.example.com/app',
284
+ public: 'https://api.example.com/public'
285
+ },
286
+ urls: {
287
+ websocket: 'wss://api.example.com'
288
+ }
289
+ }
290
+ }
291
+ }}
292
+ adapters={{
293
+ User: parseUser,
294
+ Message: parseMessage
295
+ }}
296
+ translations={{
297
+ 'welcome': 'Welcome!',
298
+ 'save': 'Save',
299
+ 'cancel': 'Cancel'
300
+ }}
301
+ >
302
+ <YourApp />
303
+ </Metropolis>
304
+ );
305
+ };
306
+ ```
307
+
308
+ ### Environment Detection
309
+
310
+ MetropolisJS automatically detects the environment based on:
311
+
312
+ 1. The `environment` property in your config
313
+ 2. `process.env.stage` (if set)
314
+ 3. `process.env.NODE_ENV` (fallback)
315
+ 4. Defaults to `'local'` if none are set
316
+
317
+ The configuration system will merge environment-specific settings with default values, allowing you to override only what you need.
318
+
319
+ ### User Authentication Example
320
+
321
+ ```tsx
322
+ import {useUserActions} from '@nlabs/metropolisjs';
323
+
324
+ const LoginForm = () => {
325
+ const userActions = useUserActions(); // Specialized hook - only creates user actions
326
+ const [username, setUsername] = useState('');
327
+ const [password, setPassword] = useState('');
328
+
329
+ const handleLogin = async () => {
330
+ try {
331
+ const session = await userActions.signIn(username, password);
332
+ console.log('User logged in successfully!', session);
333
+ } catch (error) {
334
+ console.error('Login failed:', error);
335
+ }
336
+ };
337
+
338
+ return (
339
+ <form onSubmit={handleLogin}>
340
+ <input
341
+ value={username}
342
+ onChange={(e) => setUsername(e.target.value)}
343
+ placeholder="Username"
344
+ />
345
+ <input
346
+ type="password"
347
+ value={password}
348
+ onChange={(e) => setPassword(e.target.value)}
349
+ placeholder="Password"
350
+ />
351
+ <button type="submit">Sign In</button>
352
+ </form>
353
+ );
354
+ };
355
+ ```
356
+
357
+ ### Real-Time Messaging
358
+
359
+ ```tsx
360
+ import {useMessageActions, useWebsocketActions} from '@nlabs/metropolisjs';
361
+
362
+ const ChatComponent = () => {
363
+ const messageActions = useMessageActions();
364
+ const websocketActions = useWebsocketActions();
365
+ const [messages, setMessages] = useState([]);
366
+
367
+ useEffect(() => {
368
+ // Initialize WebSocket connection
369
+ websocketActions.wsInit();
370
+
371
+ // Load existing messages
372
+ messageActions.list().then(setMessages);
373
+ }, []);
374
+
375
+ const sendMessage = async (content) => {
376
+ await messageActions.add({ content });
377
+ // Message automatically appears in real-time for all connected users!
378
+ };
379
+
380
+ return (
381
+ <div>
382
+ {messages.map(message => (
383
+ <div key={message.messageId}>{message.content}</div>
384
+ ))}
385
+ <button onClick={() => sendMessage('Hello World!')}>
386
+ Send Message
387
+ </button>
388
+ </div>
389
+ );
390
+ };
391
+ ```
392
+
393
+ ## Architecture
394
+
395
+ MetropolisJS is built on a powerful three-layer architecture with modern React patterns:
396
+
397
+ ```
398
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
399
+ │ React App │ │ MetropolisJS │ │ Reaktor │
400
+ │ │◄──►│ │◄──►│ Backend │
401
+ │ UI Layer │ │ Integration │ │ Services │
402
+ └─────────────────┘ └─────────────────┘ └─────────────────┘
403
+ │ │
404
+ │ ▼
405
+ │ ┌─────────────────┐
406
+ │ │ ArkhamJS │
407
+ │ │ Data Store │
408
+ │ │ │
409
+ │ └─────────────────┘
410
+
411
+
412
+ ┌─────────────────┐
413
+ │ React Context │
414
+ │ (Config/Flux) │
415
+ └─────────────────┘
416
+ ```
417
+
418
+ ### Core Components
419
+
420
+ - **Actions**: Handle all API interactions and business logic (factory pattern)
421
+ - **Adapters**: Transform data between frontend and backend formats
422
+ - **Stores**: Manage application state with ArkhamJS
423
+ - **WebSocket Actions**: Handle real-time communication
424
+ - **Configuration**: Context-based configuration (React best practices)
425
+ - **Hooks**: Specialized hooks for accessing actions and configuration
426
+
427
+ ### Modern Architecture Features
428
+
429
+ MetropolisJS follows React best practices:
430
+
431
+ - **Context-Based Configuration**: No global state, configuration through React Context
432
+ - **Factory Pattern**: Functional action creation with dependency injection
433
+ - **Selective Action Creation**: Only create actions you need for better performance
434
+ - **Type Safety**: Full TypeScript support with proper type inference
435
+ - **Specialized Hooks**: Individual hooks for each action type
436
+ - **Flux State Integration**: Configuration stored in flux state for non-React code access
437
+
438
+ ## Available Actions
439
+
440
+ MetropolisJS provides comprehensive actions for all your needs. Access them using specialized hooks or the main `useMetropolis()` hook:
441
+
442
+ ### Specialized Hooks (Recommended)
443
+
444
+ - `useUserActions()` - Authentication, personas, user management
445
+ - `useMessageActions()` - Real-time messaging and conversations
446
+ - `usePermissionActions()` - Permission and role management (RBAC)
447
+ - `usePostActions()` - Social media posts and content
448
+ - `useReactionActions()` - Likes, reactions, and interactions
449
+ - `useTagActions()` - Content categorization and discovery
450
+ - `useEventActions()` - Event management and scheduling
451
+ - `useImageActions()` - Media upload and management
452
+ - `useLocationActions()` - Geolocation and location-based features
453
+ - `useWebsocketActions()` - Real-time communication setup
454
+ - `useContentActions()` - Content management
455
+ - `usePersonaActions()` - Persona management
456
+ - `useTranslationActions()` - Translation management
457
+
458
+ ### Using Collection Actions
459
+
460
+ ```tsx
461
+ // Recommended: Use specialized hooks (only creates what you need)
462
+ const userActions = useUserActions();
463
+ const postActions = usePostActions();
464
+ const permissionActions = usePermissionActions();
465
+
466
+ // Alternative: Selective creation
467
+ const {userActions, postActions, permissionActions} = useMetropolis(['user', 'post', 'permission']);
468
+
469
+ // Alternative: All actions (creates all action types)
470
+ const {userActions, postActions, messageActions, permissionActions} = useMetropolis();
471
+ ```
472
+
473
+ ## Factory Pattern Guide
474
+
475
+ MetropolisJS has been refactored to use a **factory function pattern** for actions instead of class-based approaches. This provides better functional programming practices, improved testability, and enhanced flexibility through dependency injection.
476
+
477
+ ### Key Benefits
478
+
479
+ 1. **Functional Programming**: Pure functions instead of classes with side effects
480
+ 2. **Better Testability**: Easier to mock and test individual functions
481
+ 3. **Composability**: Actions can be easily combined and extended
482
+ 4. **Dependency Injection**: Custom adapters can be injected and merged with defaults
483
+ 5. **Backward Compatibility**: Legacy class wrappers maintain existing API compatibility
484
+
485
+ ### Basic Usage
486
+
487
+ #### Before (Class-based)
488
+
489
+ ```typescript
490
+ import {userActions} from '../actions/userActions';
491
+
492
+ const userActions = new userActions(flux);
493
+ const user = await userActions.add(userData);
494
+ ```
495
+
496
+ #### After (Factory Pattern)
497
+
498
+ ```typescript
499
+ import {createUserActions} from '../actions/userActions';
500
+
501
+ const userActions = createUserActions(flux);
502
+ const user = await userActions.add(userData);
503
+ ```
504
+
505
+ ### Advanced Usage with Custom Adapters
506
+
507
+ #### Custom Validation Adapter
508
+
509
+ ```typescript
510
+ // Custom adapter that extends default behavior
511
+ const customUserAdapter = (input: unknown, options?: UserAdapterOptions) => {
512
+ // input is already validated by default adapter
513
+ const user = input as any;
514
+
515
+ // Add business-specific validation
516
+ if (user.email && !user.email.includes('@company.com')) {
517
+ throw new Error('Only company emails allowed');
518
+ }
519
+
520
+ // Add computed fields
521
+ return {
522
+ ...user,
523
+ fullName: `${user.firstName || ''} ${user.lastName || ''}`.trim(),
524
+ isAdmin: user.userAccess >= 3
525
+ };
526
+ };
527
+
528
+ const userActions = createUserActions(flux, {
529
+ userAdapter: customUserAdapter
530
+ });
531
+ ```
532
+
533
+ #### Configuration-based Adapters
534
+
535
+ ```typescript
536
+ const userActions = createUserActions(flux, {
537
+ userAdapterOptions: {
538
+ strict: true,
539
+ environment: 'production',
540
+ customValidation: (input) => {
541
+ // Additional validation logic
542
+ return input;
543
+ }
544
+ }
545
+ });
546
+ ```
547
+
548
+ #### Runtime Adapter Updates
549
+
550
+ ```typescript
551
+ const userActions = createUserActions(flux);
552
+
553
+ // Update adapter at runtime
554
+ userActions.updateUserAdapter(customUserAdapter);
555
+
556
+ // Update options at runtime
557
+ userActions.updateUserAdapterOptions({
558
+ strict: true,
559
+ environment: 'production'
560
+ });
561
+ ```
562
+
563
+ ### Available Factory Functions
564
+
565
+ All action files now export factory functions:
566
+
567
+ - `createUserActions(flux, options?)` - User management
568
+ - `createPostActions(flux, options?)` - Post management
569
+ - `createEventActions(flux, options?)` - Event management
570
+ - `createMessageActions(flux, options?)` - Messaging
571
+ - `createImageActions(flux, options?)` - Image handling
572
+ - `createLocationActions(flux, options?)` - Location services
573
+ - `createReactionActions(flux, options?)` - Reactions
574
+ - `createTagActions(flux, options?)` - Tag management
575
+ - `createWebsocketActions(flux)` - WebSocket connections
576
+
577
+ ### Adapter Options Interface
578
+
579
+ All adapters support the same options interface:
580
+
581
+ ```typescript
582
+ interface AdapterOptions {
583
+ strict?: boolean; // Enable strict validation
584
+ allowPartial?: boolean; // Allow partial data
585
+ environment?: 'development' | 'production' | 'test';
586
+ customValidation?: (input: unknown) => unknown;
587
+ }
588
+ ```
589
+
590
+ ### Migration Guide
591
+
592
+ #### Step 1: Update Imports
593
+
594
+ ```typescript
595
+ // Old
596
+ import {userActions} from '../actions/userActions';
597
+
598
+ // New
599
+ import {createUserActions} from '../actions/userActions';
600
+ ```
601
+
602
+ #### Step 2: Update Instantiation
603
+
604
+ ```typescript
605
+ // Old
606
+ const userActions = new userActions(flux, customAdapter);
607
+
608
+ // New
609
+ const userActions = createUserActions(flux, {
610
+ userAdapter: customAdapter
611
+ });
612
+ ```
613
+
614
+ #### Step 3: Using Actions in Components
615
+
616
+ The recommended approach is to use specialized hooks:
617
+
618
+ ```typescript
619
+ // Recommended: Use specialized hooks
620
+ import {useUserActions, usePostActions} from '@nlabs/metropolisjs';
621
+
622
+ const MyComponent = () => {
623
+ const userActions = useUserActions();
624
+ const postActions = usePostActions();
625
+ // ...
626
+ };
627
+
628
+ // Alternative: Use useMetropolis with selective creation
629
+ import {useMetropolis} from '@nlabs/metropolisjs';
630
+
631
+ const MyComponent = () => {
632
+ const {userActions, postActions} = useMetropolis(['user', 'post']);
633
+ // ...
634
+ };
635
+ ```
636
+
637
+ ### Configuration Access
638
+
639
+ Access configuration using React hooks:
640
+
641
+ ```typescript
642
+ import {useMetropolisConfig} from '@nlabs/metropolisjs';
643
+
644
+ const MyComponent = () => {
645
+ const config = useMetropolisConfig();
646
+ const apiUrl = config.app?.api?.url;
647
+ // ...
648
+ };
649
+ ```
650
+
651
+ For non-React code (actions, utilities), use:
652
+
653
+ ```typescript
654
+ import {getConfigFromFlux} from '@nlabs/metropolisjs';
655
+
656
+ const config = getConfigFromFlux(flux);
657
+ const apiUrl = config.app?.api?.url || '';
658
+ ```
659
+
660
+ **Note:** The `Config` class has been removed. Use `useMetropolisConfig()` in React components or `getConfigFromFlux()` in non-React code.
661
+
662
+ ### Testing Examples
663
+
664
+ #### Unit Testing Actions
665
+
666
+ ```typescript
667
+ import {createUserActions} from '@nlabs/metropolisjs';
668
+
669
+ describe('userActions', () => {
670
+ let flux: FluxFramework;
671
+ let userActions: userActions;
672
+
673
+ beforeEach(() => {
674
+ flux = createMockFlux();
675
+ // Store config in flux state for actions to access
676
+ flux.setState('app.config', {
677
+ app: { api: { url: 'http://localhost:3000/app' } }
678
+ });
679
+ userActions = createUserActions(flux);
680
+ });
681
+
682
+ it('should add user with validation', async () => {
683
+ const userData = {username: 'test', email: 'test@example.com'};
684
+ const result = await userActions.add(userData);
685
+ expect(result).toBeDefined();
686
+ });
687
+ });
688
+ ```
689
+
690
+ #### Testing with Custom Adapters
691
+
692
+ ```typescript
693
+ const mockAdapter = jest.fn((input) => ({
694
+ ...input,
695
+ validated: true
696
+ }));
697
+
698
+ const userActions = createUserActions(flux, {
699
+ userAdapter: mockAdapter
700
+ });
701
+
702
+ expect(mockAdapter).toHaveBeenCalled();
703
+ ```
704
+
705
+ #### Testing React Components
706
+
707
+ ```typescript
708
+ import {renderHook} from '@testing-library/react';
709
+ import {Metropolis, useUserActions} from '@nlabs/metropolisjs';
710
+
711
+ describe('useUserActions', () => {
712
+ it('should return user actions', () => {
713
+ const wrapper = ({children}) => (
714
+ <Metropolis config={{development: {app: {api: {url: 'http://localhost'}}}}}>
715
+ {children}
716
+ </Metropolis>
717
+ );
718
+
719
+ const {result} = renderHook(() => useUserActions(), {wrapper});
720
+ expect(result.current).toBeDefined();
721
+ expect(result.current.add).toBeDefined();
722
+ });
723
+ });
724
+ ```
725
+
726
+ ### Best Practices
727
+
728
+ 1. **Use Specialized Hooks**: Prefer `useUserActions()` over `useMetropolis()` when you only need one action type
729
+ 2. **Selective Creation**: Use `useMetropolis(['user', 'post'])` when you need multiple specific actions
730
+ 3. **Context-Based Config**: Use `useMetropolisConfig()` for accessing configuration
731
+ 4. **Leverage Adapter Injection**: Pass custom adapters through the `Metropolis` component
732
+ 5. **Type Safety**: Always use TypeScript interfaces for better type checking
733
+ 6. **Error Handling**: Custom adapters should throw meaningful errors
734
+ 7. **Wrap Components**: Always wrap components using hooks with `<Metropolis>` provider
735
+
736
+ ### Removed APIs
737
+
738
+ The following APIs have been removed:
739
+
740
+ - `Config.get()` - Use `useMetropolisConfig()` in React components or `getConfigFromFlux(flux)` in non-React code
741
+ - `Config.set()` - Pass configuration to the `<Metropolis>` component instead
742
+
743
+ ### Performance Considerations
744
+
745
+ - **Specialized hooks** only create the specific action type (best performance)
746
+ - **Selective creation** creates only requested actions
747
+ - Factory functions are lightweight and create minimal overhead
748
+ - Adapter validation is only performed when needed
749
+ - Options are merged efficiently without deep cloning
750
+ - Better tree-shaking opportunities with specialized hooks
751
+
752
+ ## Adapters
753
+
754
+ Customize data transformation with powerful adapters. Pass adapters to the `Metropolis` component:
755
+
756
+ - **User**: User account and authentication data
757
+ - **Permission**: Permission and role data with RBAC support
758
+ - **Message**: Chat and messaging data
759
+ - **Post**: Social media content
760
+ - **Event**: Event and scheduling data
761
+ - **Image**: Media and file data
762
+ - **Location**: Geolocation data
763
+ - **Tag**: Categorization data
764
+ - **Reaction**: User interaction data
765
+ - **Content**: Content management
766
+ - **Persona**: Persona management
767
+ - **Translation**: Translation data
768
+
769
+ ## Real-Time Features
770
+
771
+ ### WebSocket Integration
772
+
773
+ ```tsx
774
+ import {useWebsocketActions} from '@nlabs/metropolisjs';
775
+
776
+ const MyComponent = () => {
777
+ const websocketActions = useWebsocketActions();
778
+
779
+ useEffect(() => {
780
+ // Initialize real-time connections
781
+ websocketActions.wsInit();
782
+ }, []);
783
+
784
+ // Messages, notifications, and data updates
785
+ // are automatically synchronized across all clients
786
+ };
787
+ ```
788
+
789
+ ### Server-Sent Events
790
+
791
+ Built-in SSE support for lightweight real-time updates without the overhead of WebSocket connections.
792
+
793
+ ## Customization
794
+
795
+ ### Custom Data Adapters
796
+
797
+ You can customize data transformation by providing custom adapters. Adapters are functions that transform and validate data:
798
+
799
+ ```tsx
800
+ // Custom adapter function
801
+ const customUserAdapter = (input: unknown, options?: UserAdapterOptions) => {
802
+ const user = input as any;
803
+
804
+ // Add custom transformation logic
805
+ return {
806
+ ...user,
807
+ displayName: `${user.firstName || ''} ${user.lastName || ''}`.trim(),
808
+ customField: 'custom value',
809
+ isVerified: user.email?.endsWith('@company.com')
810
+ };
811
+ };
812
+
813
+ // Pass adapters through the Metropolis component (recommended)
814
+ <Metropolis
815
+ adapters={{
816
+ User: customUserAdapter,
817
+ Message: customMessageAdapter
818
+ }}
819
+ >
820
+ <YourApp />
821
+ </Metropolis>
822
+ ```
823
+
824
+ The adapters will be automatically used by all action hooks. For more details on the factory pattern and adapter customization, see the [Factory Pattern Guide](#-factory-pattern-guide) section above.
825
+
826
+ ### Accessing Configuration
827
+
828
+ ```tsx
829
+ import {useMetropolisConfig} from '@nlabs/metropolisjs';
830
+
831
+ const MyComponent = () => {
832
+ const config = useMetropolisConfig();
833
+ const apiUrl = config.app?.api?.url;
834
+ const websocketUrl = config.app?.urls?.websocket;
835
+
836
+ // Use configuration values
837
+ return <div>API: {apiUrl}</div>;
838
+ };
839
+ ```
840
+
841
+ **Note:** `useMetropolisConfig()` must be used within a component wrapped by `<Metropolis>`.
842
+
843
+ ## Performance Features
844
+
845
+ - **Selective Action Creation** - Only create actions you need with specialized hooks
846
+ - **Debounced API calls** - Prevent excessive requests
847
+ - **Intelligent caching** - With ArkhamJS
848
+ - **Optimistic updates** - Instant UI feedback
849
+ - **Connection pooling** - WebSocket efficiency
850
+ - **Lazy loading** - Support for large datasets
851
+ - **Tree-shaking friendly** - Better bundle optimization
852
+
853
+ ## Security
854
+
855
+ - **Automatic token refresh** for seamless sessions
856
+ - **Secure WebSocket connections** with authentication
857
+ - **Input validation** and sanitization
858
+ - **CSRF protection** built-in
859
+ - **Session management** with configurable timeouts
860
+ - **5-Level RBAC permission system** for granular access control
861
+
862
+ ## Permission System (RBAC)
863
+
864
+ MetropolisJS includes a comprehensive 5-level Role-Based Access Control (RBAC) system that integrates seamlessly with the Reaktor backend. This system provides granular control over user permissions and access levels throughout your application.
865
+
866
+ ### Permission Levels
867
+
868
+ The system defines five hierarchical permission levels:
869
+
870
+ ```typescript
871
+ enum PermissionLevel {
872
+ GUEST = 0, // Unauthenticated users
873
+ USER = 1, // Authenticated users
874
+ MODERATOR = 2, // Content moderators
875
+ ADMIN = 3, // Application administrators
876
+ SUPER_ADMIN = 4 // System administrators
877
+ }
878
+ ```
879
+
880
+ | Level | Name | Value | Description |
881
+ |-------|------|-------|-------------|
882
+ | 0 | Guest | `PermissionLevel.GUEST` | Unauthenticated users with limited read access |
883
+ | 1 | User | `PermissionLevel.USER` | Authenticated users who can create and edit their own content |
884
+ | 2 | Moderator | `PermissionLevel.MODERATOR` | Can moderate content and manage users |
885
+ | 3 | Admin | `PermissionLevel.ADMIN` | Full access to application features |
886
+ | 4 | Super Admin | `PermissionLevel.SUPER_ADMIN` | Complete system access, can manage admins |
887
+
888
+ ### Using the Permission System
889
+
890
+ #### 1. Permission Hook
891
+
892
+ The `usePermissions()` hook provides comprehensive permission checking capabilities:
893
+
894
+ ```tsx
895
+ import { usePermissions, PermissionLevel } from '@nlabs/metropolisjs';
896
+
897
+ const MyComponent = () => {
898
+ const {
899
+ userLevel, // Current user's permission level
900
+ isGuest, // Boolean checks
901
+ isUser,
902
+ isModerator,
903
+ isAdmin,
904
+ isSuperAdmin,
905
+ hasPermission, // Function to check specific level
906
+ checkResource // Function to check resource-specific permissions
907
+ } = usePermissions();
908
+
909
+ return (
910
+ <div>
911
+ <p>Your level: {userLevel}</p>
912
+ {isAdmin && <button>Admin Panel</button>}
913
+ {hasPermission(PermissionLevel.MODERATOR) && (
914
+ <button>Moderate Content</button>
915
+ )}
916
+ </div>
917
+ );
918
+ };
919
+ ```
920
+
921
+ #### 2. Permission Guard Component
922
+
923
+ Conditionally render components based on permission requirements:
924
+
925
+ ```tsx
926
+ import { PermissionGuard, PermissionLevel } from '@nlabs/metropolisjs';
927
+
928
+ const ProtectedContent = () => {
929
+ return (
930
+ <>
931
+ <PermissionGuard
932
+ requiredLevel={PermissionLevel.USER}
933
+ fallback={<p>Please log in to view this content</p>}
934
+ >
935
+ <p>This content is visible to authenticated users</p>
936
+ </PermissionGuard>
937
+
938
+ <PermissionGuard
939
+ requiredLevel={PermissionLevel.ADMIN}
940
+ fallback={null} // Hides content completely
941
+ >
942
+ <button>Admin Settings</button>
943
+ </PermissionGuard>
944
+
945
+ <PermissionGuard
946
+ requiredLevel={PermissionLevel.MODERATOR}
947
+ resource="posts" // Resource-specific permission
948
+ fallback={<p>Moderator access required</p>}
949
+ >
950
+ <button>Moderate Posts</button>
951
+ </PermissionGuard>
952
+ </>
953
+ );
954
+ };
955
+ ```
956
+
957
+ #### 3. Managing Permissions with Actions
958
+
959
+ Use `usePermissionActions()` to manage permissions programmatically:
960
+
961
+ ```tsx
962
+ import { usePermissionActions, PermissionLevel } from '@nlabs/metropolisjs';
963
+
964
+ const PermissionManager = () => {
965
+ const permissionActions = usePermissionActions();
966
+
967
+ const grantModeratorRole = async (userId: string) => {
968
+ try {
969
+ const permission = await permissionActions.add({
970
+ userId,
971
+ name: 'Moderator Role',
972
+ level: PermissionLevel.MODERATOR,
973
+ resource: 'posts',
974
+ description: 'Can moderate posts and comments'
975
+ });
976
+ console.log('Permission granted:', permission);
977
+ } catch (error) {
978
+ console.error('Failed to grant permission:', error);
979
+ }
980
+ };
981
+
982
+ const checkUserAccess = async (userId: string) => {
983
+ const hasAccess = await permissionActions.check(
984
+ userId,
985
+ 'posts',
986
+ PermissionLevel.MODERATOR
987
+ );
988
+ return hasAccess;
989
+ };
990
+
991
+ const loadUserPermissions = async (userId: string) => {
992
+ const permissions = await permissionActions.listByUser(userId);
993
+ return permissions;
994
+ };
995
+
996
+ return (
997
+ <div>
998
+ <button onClick={() => grantModeratorRole('user123')}>
999
+ Grant Moderator Permission
1000
+ </button>
1001
+ </div>
1002
+ );
1003
+ };
1004
+ ```
1005
+
1006
+ #### 4. Resource-Specific Permissions
1007
+
1008
+ The permission system supports resource-specific access control:
1009
+
1010
+ ```tsx
1011
+ import { usePermissions, PermissionLevel } from '@nlabs/metropolisjs';
1012
+
1013
+ const ResourceProtectedComponent = () => {
1014
+ const { checkResource } = usePermissions();
1015
+
1016
+ const canEditPosts = checkResource('posts', PermissionLevel.MODERATOR);
1017
+ const canDeleteUsers = checkResource('users', PermissionLevel.ADMIN);
1018
+ const canViewReports = checkResource('reports', PermissionLevel.MODERATOR);
1019
+
1020
+ return (
1021
+ <div>
1022
+ {canEditPosts && <button>Edit Post</button>}
1023
+ {canDeleteUsers && <button>Delete User</button>}
1024
+ {canViewReports && <button>View Reports</button>}
1025
+ </div>
1026
+ );
1027
+ };
1028
+ ```
1029
+
1030
+ ### Backward Compatibility
1031
+
1032
+ The permission system is fully backward compatible with the existing `userAccess` field in the User model. The `userAccess` number (0-4) directly maps to the `PermissionLevel` enum values, ensuring seamless integration with existing code.
1033
+
1034
+ ### Available Permission Actions
1035
+
1036
+ The `usePermissionActions()` hook provides the following methods:
1037
+
1038
+ - **`add(permissionData)`** - Grant a new permission
1039
+ - **`check(userId, resource, requiredLevel)`** - Check if a user has access
1040
+ - **`itemById(permissionId)`** - Retrieve a specific permission
1041
+ - **`list(from?, to?)`** - List all permissions with pagination
1042
+ - **`listByUser(userId)`** - Get all permissions for a specific user
1043
+ - **`remove(permissionId)`** - Revoke a permission
1044
+ - **`update(permission)`** - Update an existing permission
1045
+
1046
+ ### Integration with Reaktor Backend
1047
+
1048
+ The permission system integrates with the Reaktor backend through GraphQL mutations and queries:
1049
+
1050
+ ```graphql
1051
+ # Grant permission
1052
+ mutation {
1053
+ permissions {
1054
+ add(permission: {
1055
+ userId: "user123"
1056
+ level: 2
1057
+ resource: "posts"
1058
+ name: "Moderator"
1059
+ }) {
1060
+ permissionId
1061
+ level
1062
+ resource
1063
+ }
1064
+ }
1065
+ }
1066
+
1067
+ # Check permission
1068
+ query {
1069
+ permissions {
1070
+ check(
1071
+ userId: "user123"
1072
+ resource: "posts"
1073
+ requiredLevel: 2
1074
+ )
1075
+ }
1076
+ }
1077
+
1078
+ # List user permissions
1079
+ query {
1080
+ permissions {
1081
+ listByUser(userId: "user123") {
1082
+ permissionId
1083
+ name
1084
+ level
1085
+ resource
1086
+ description
1087
+ }
1088
+ }
1089
+ }
1090
+ ```
1091
+
1092
+ ### Best Practices
1093
+
1094
+ 1. **Use Permission Guards for UI**: Wrap sensitive UI elements with `<PermissionGuard>` components
1095
+ 2. **Check Permissions in Actions**: Always verify permissions before executing sensitive operations
1096
+ 3. **Resource-Specific Permissions**: Use resource-based permissions for fine-grained control
1097
+ 4. **Leverage Boolean Helpers**: Use `isAdmin`, `isModerator`, etc. for cleaner code
1098
+ 5. **Test Permission Logic**: Write tests for permission checks to ensure security
1099
+ 6. **Document Required Levels**: Clearly document what permission level each feature requires
1100
+
1101
+ ### Example: Complete Permission Workflow
1102
+
1103
+ ```tsx
1104
+ import {
1105
+ Metropolis,
1106
+ usePermissions,
1107
+ usePermissionActions,
1108
+ PermissionGuard,
1109
+ PermissionLevel
1110
+ } from '@nlabs/metropolisjs';
1111
+
1112
+ const App = () => {
1113
+ return (
1114
+ <Metropolis config={{/* your config */}}>
1115
+ <Dashboard />
1116
+ </Metropolis>
1117
+ );
1118
+ };
1119
+
1120
+ const Dashboard = () => {
1121
+ const { isAdmin, isModerator, userLevel } = usePermissions();
1122
+ const permissionActions = usePermissionActions();
1123
+
1124
+ return (
1125
+ <div>
1126
+ <h1>Dashboard - Level: {userLevel}</h1>
1127
+
1128
+ {/* Everyone sees this */}
1129
+ <section>
1130
+ <h2>Public Content</h2>
1131
+ </section>
1132
+
1133
+ {/* Only authenticated users */}
1134
+ <PermissionGuard requiredLevel={PermissionLevel.USER}>
1135
+ <section>
1136
+ <h2>User Content</h2>
1137
+ <button>Create Post</button>
1138
+ </section>
1139
+ </PermissionGuard>
1140
+
1141
+ {/* Only moderators and above */}
1142
+ {isModerator && (
1143
+ <section>
1144
+ <h2>Moderation Tools</h2>
1145
+ <button>Review Content</button>
1146
+ </section>
1147
+ )}
1148
+
1149
+ {/* Only admins */}
1150
+ {isAdmin && (
1151
+ <section>
1152
+ <h2>Admin Panel</h2>
1153
+ <button>Manage Users</button>
1154
+ <button>System Settings</button>
1155
+ </section>
1156
+ )}
1157
+ </div>
1158
+ );
1159
+ };
1160
+ ```
1161
+
1162
+ For more detailed examples, see [`examples/permission-system-usage.tsx`](./examples/permission-system-usage.tsx).
1163
+
1164
+ ## 📦 Installation & Setup
1165
+
1166
+ ### Prerequisites
1167
+
1168
+ - Node.js 16+
1169
+ - React 18+
1170
+ - TypeScript 4.5+
1171
+
1172
+ ### Full Installation
1173
+
1174
+ ```bash
1175
+ # Install MetropolisJS and dependencies
1176
+ npm install @nlabs/metropolisjs @nlabs/arkhamjs @nlabs/arkhamjs-utils-react
1177
+
1178
+ # For development
1179
+ npm install --save-dev @types/react @types/node
1180
+ ```
1181
+
1182
+ ### Environment Setup
1183
+
1184
+ MetropolisJS automatically detects the environment from:
1185
+
1186
+ - `process.env.stage` (if set)
1187
+ - `process.env.NODE_ENV` (fallback)
1188
+ - Defaults to `'local'` if none are set
1189
+
1190
+ Configure your environment-specific settings in the `config` prop of the `Metropolis` component.
1191
+
1192
+ ## Contributing
1193
+
1194
+ We love contributions! Here's how you can help:
1195
+
1196
+ 1. **Fork** the repository
1197
+ 2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)
1198
+ 3. **Commit** your changes (`git commit -m 'Add amazing feature'`)
1199
+ 4. **Push** to the branch (`git push origin feature/amazing-feature`)
1200
+ 5. **Open** a Pull Request
1201
+
1202
+ ## License
1203
+
1204
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
1205
+
1206
+ ## Additional Documentation
1207
+
1208
+ - **[Factory Pattern Guide](./factoryPatternGuide.md)** - Detailed guide on using the factory pattern
1209
+ - **[Architecture Analysis](./ARCHITECTURE_ANALYSIS.md)** - Deep dive into the architecture
1210
+ - **[Changelog](./CHANGELOG.md)** - Complete list of changes and improvements
1211
+
1212
+ ## Support
1213
+
1214
+ - **Documentation**: See above for detailed guides
1215
+ - **Issues**: [GitHub Issues](https://github.com/nitrogenlabs/metropolisjs/issues)
1216
+ - **Discussions**: [GitHub Discussions](https://github.com/nitrogenlabs/metropolisjs/discussions)
1217
+ - **Email**: <giraldo@nitrogenlabs.com>
1218
+
1219
+ ## About Nitrogen Labs
1220
+
1221
+ MetropolisJS is proudly developed by [Nitrogen Labs](http://nitrogenlabs.com), a team passionate about building powerful, developer-friendly tools that make web development faster, more reliable, and more enjoyable.
1222
+
1223
+ ---
1224
+
1225
+ **Ready to build the future?** Start with MetropolisJS today and experience the power of seamless frontend-backend integration! 🚀
1226
+
1227
+ ## CRUD Operations
1228
+
1229
+ MetropolisJS now provides comprehensive CRUD (Create, Read, Update, Delete) operations for all Reaktor collections:
1230
+
1231
+ ### Supported Collections
1232
+
1233
+ - **users** - User accounts and authentication data
1234
+ - **posts** - User posts and content
1235
+ - **groups** - Group entities and communities
1236
+ - **messages** - Direct messages
1237
+ - **conversations** - Conversation threads
1238
+ - **files** - File attachments
1239
+ - **images** - Image media
1240
+ - **videos** - Video media
1241
+ - **apps** - Application entities
1242
+ - **personas** - Extended user persona details
1243
+ - **tags** - Tag entities for categorization
1244
+
1245
+ ### Basic CRUD Example
1246
+
1247
+ ```tsx
1248
+ import {useFlux} from '@nlabs/arkhamjs-utils-react';
1249
+ import {createPostActions, createGroupActions} from '@nlabs/metropolisjs';
1250
+
1251
+ const MyComponent = () => {
1252
+ const flux = useFlux();
1253
+ const postActions = createPostActions(flux);
1254
+ const groupActions = createGroupActions(flux);
1255
+
1256
+ // Create
1257
+ const createPost = async () => {
1258
+ const post = await postActions.add({
1259
+ content: "Hello World",
1260
+ userId: "user123",
1261
+ name: "My First Post"
1262
+ });
1263
+ };
1264
+
1265
+ // Read
1266
+ const getPost = async (postId: string) => {
1267
+ const post = await postActions.itemById(postId);
1268
+ };
1269
+
1270
+ // Update
1271
+ const updatePost = async (postId: string) => {
1272
+ await postActions.update({
1273
+ postId,
1274
+ content: "Updated content"
1275
+ });
1276
+ };
1277
+
1278
+ // Delete
1279
+ const deletePost = async (postId: string) => {
1280
+ await postActions.delete(postId);
1281
+ };
1282
+
1283
+ // List with pagination
1284
+ const listPosts = async () => {
1285
+ const posts = await postActions.listByLatest(0, 10);
1286
+ };
1287
+ };
1288
+ ```
1289
+
1290
+ ### Relationship Management
1291
+
1292
+ Connect and manage relationships between collections:
1293
+
1294
+ ```tsx
1295
+ import {createConnectionActions, CONNECTION_TYPES} from '@nlabs/metropolisjs';
1296
+
1297
+ const connectionActions = createConnectionActions(flux);
1298
+
1299
+ // Add user to group
1300
+ await connectionActions.addConnection(
1301
+ 'users',
1302
+ userId,
1303
+ 'groups',
1304
+ groupId,
1305
+ CONNECTION_TYPES.MEMBER
1306
+ );
1307
+
1308
+ // Get all connections
1309
+ const connections = await connectionActions.getConnections('users', userId);
1310
+
1311
+ // Remove connection
1312
+ await connectionActions.removeConnection('users', userId, 'groups', groupId);
1313
+ ```
1314
+
1315
+ ### Extensible Fields
1316
+
1317
+ All CRUD operations support custom fields:
1318
+
1319
+ ```tsx
1320
+ const post = await postActions.add({
1321
+ content: "Hello",
1322
+ userId: "user123",
1323
+ // Custom fields
1324
+ customField1: "value",
1325
+ customField2: 42,
1326
+ metadata: {
1327
+ source: "mobile",
1328
+ version: "1.0"
1329
+ }
1330
+ });
1331
+ ```
1332
+
1333
+ ### Documentation
1334
+
1335
+ For comprehensive guides and examples, see:
1336
+
1337
+ - [CRUD Integration Guide](./docs/CRUD_INTEGRATION.md) - Complete guide to CRUD operations
1338
+ - [Actions Reference](./docs/ACTIONS.md) - Action families, hooks, creators, and method map
1339
+ - [Collections Reference](./docs/COLLECTIONS.md) - Detailed information about each collection
1340
+ - [Connections Guide](./docs/CONNECTIONS.md) - Managing relationships between collections
1341
+ - [CRUD Examples](./examples/crud-usage.tsx) - Practical code examples
1342
+ - [Connection Examples](./examples/connections-usage.tsx) - Relationship management examples
1343
+ - [Extensibility Examples](./examples/extensibility-usage.tsx) - Custom field examples