@powerhousedao/reactor-api 6.0.0-staging.4 → 6.0.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 (338) hide show
  1. package/README.md +6 -0
  2. package/dist/index.d.mts +3085 -0
  3. package/dist/index.d.mts.map +1 -0
  4. package/dist/index.mjs +6720 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/dist/src/packages/https-hooks.d.mts +39 -0
  7. package/dist/src/packages/https-hooks.d.mts.map +1 -0
  8. package/dist/src/packages/https-hooks.mjs +82 -0
  9. package/dist/src/packages/https-hooks.mjs.map +1 -0
  10. package/dist/src/packages/vite-loader.d.mts +29 -0
  11. package/dist/src/packages/vite-loader.d.mts.map +1 -0
  12. package/dist/src/packages/vite-loader.mjs +145 -0
  13. package/dist/src/packages/vite-loader.mjs.map +1 -0
  14. package/dist/types-Do4QTfT3.d.mts +37 -0
  15. package/dist/types-Do4QTfT3.d.mts.map +1 -0
  16. package/dist/utils-BFkbSO_H.mjs +296 -0
  17. package/dist/utils-BFkbSO_H.mjs.map +1 -0
  18. package/package.json +60 -42
  19. package/dist/codegen.d.ts +0 -4
  20. package/dist/codegen.d.ts.map +0 -1
  21. package/dist/codegen.js +0 -38
  22. package/dist/codegen.js.map +0 -1
  23. package/dist/index.d.ts +0 -14
  24. package/dist/index.d.ts.map +0 -1
  25. package/dist/index.js +0 -14
  26. package/dist/index.js.map +0 -1
  27. package/dist/src/config.d.ts +0 -6
  28. package/dist/src/config.d.ts.map +0 -1
  29. package/dist/src/config.js +0 -6
  30. package/dist/src/config.js.map +0 -1
  31. package/dist/src/graphql/analytics-subgraph.d.ts +0 -14
  32. package/dist/src/graphql/analytics-subgraph.d.ts.map +0 -1
  33. package/dist/src/graphql/analytics-subgraph.js +0 -26
  34. package/dist/src/graphql/analytics-subgraph.js.map +0 -1
  35. package/dist/src/graphql/auth/index.d.ts +0 -2
  36. package/dist/src/graphql/auth/index.d.ts.map +0 -1
  37. package/dist/src/graphql/auth/index.js +0 -2
  38. package/dist/src/graphql/auth/index.js.map +0 -1
  39. package/dist/src/graphql/auth/resolvers.d.ts +0 -149
  40. package/dist/src/graphql/auth/resolvers.d.ts.map +0 -1
  41. package/dist/src/graphql/auth/resolvers.js +0 -173
  42. package/dist/src/graphql/auth/resolvers.js.map +0 -1
  43. package/dist/src/graphql/auth/schema.graphql +0 -173
  44. package/dist/src/graphql/auth/subgraph.d.ts +0 -177
  45. package/dist/src/graphql/auth/subgraph.d.ts.map +0 -1
  46. package/dist/src/graphql/auth/subgraph.js +0 -340
  47. package/dist/src/graphql/auth/subgraph.js.map +0 -1
  48. package/dist/src/graphql/base-subgraph.d.ts +0 -20
  49. package/dist/src/graphql/base-subgraph.d.ts.map +0 -1
  50. package/dist/src/graphql/base-subgraph.js +0 -34
  51. package/dist/src/graphql/base-subgraph.js.map +0 -1
  52. package/dist/src/graphql/document-model-subgraph.d.ts +0 -103
  53. package/dist/src/graphql/document-model-subgraph.d.ts.map +0 -1
  54. package/dist/src/graphql/document-model-subgraph.js +0 -595
  55. package/dist/src/graphql/document-model-subgraph.js.map +0 -1
  56. package/dist/src/graphql/drive-subgraph.d.ts +0 -25
  57. package/dist/src/graphql/drive-subgraph.d.ts.map +0 -1
  58. package/dist/src/graphql/drive-subgraph.js +0 -488
  59. package/dist/src/graphql/drive-subgraph.js.map +0 -1
  60. package/dist/src/graphql/graphql-manager.d.ts +0 -52
  61. package/dist/src/graphql/graphql-manager.d.ts.map +0 -1
  62. package/dist/src/graphql/graphql-manager.js +0 -491
  63. package/dist/src/graphql/graphql-manager.js.map +0 -1
  64. package/dist/src/graphql/index.d.ts +0 -10
  65. package/dist/src/graphql/index.d.ts.map +0 -1
  66. package/dist/src/graphql/index.js +0 -10
  67. package/dist/src/graphql/index.js.map +0 -1
  68. package/dist/src/graphql/playground.d.ts +0 -2
  69. package/dist/src/graphql/playground.d.ts.map +0 -1
  70. package/dist/src/graphql/playground.js +0 -74
  71. package/dist/src/graphql/playground.js.map +0 -1
  72. package/dist/src/graphql/reactor/adapters.d.ts +0 -62
  73. package/dist/src/graphql/reactor/adapters.d.ts.map +0 -1
  74. package/dist/src/graphql/reactor/adapters.js +0 -270
  75. package/dist/src/graphql/reactor/adapters.js.map +0 -1
  76. package/dist/src/graphql/reactor/factory.d.ts +0 -95
  77. package/dist/src/graphql/reactor/factory.d.ts.map +0 -1
  78. package/dist/src/graphql/reactor/factory.js +0 -7
  79. package/dist/src/graphql/reactor/factory.js.map +0 -1
  80. package/dist/src/graphql/reactor/gen/graphql.d.ts +0 -1355
  81. package/dist/src/graphql/reactor/gen/graphql.d.ts.map +0 -1
  82. package/dist/src/graphql/reactor/gen/graphql.js +0 -615
  83. package/dist/src/graphql/reactor/gen/graphql.js.map +0 -1
  84. package/dist/src/graphql/reactor/index.d.ts +0 -4
  85. package/dist/src/graphql/reactor/index.d.ts.map +0 -1
  86. package/dist/src/graphql/reactor/index.js +0 -4
  87. package/dist/src/graphql/reactor/index.js.map +0 -1
  88. package/dist/src/graphql/reactor/operations.graphql +0 -336
  89. package/dist/src/graphql/reactor/pubsub.d.ts +0 -27
  90. package/dist/src/graphql/reactor/pubsub.d.ts.map +0 -1
  91. package/dist/src/graphql/reactor/pubsub.js +0 -93
  92. package/dist/src/graphql/reactor/pubsub.js.map +0 -1
  93. package/dist/src/graphql/reactor/requester.d.ts +0 -4
  94. package/dist/src/graphql/reactor/requester.d.ts.map +0 -1
  95. package/dist/src/graphql/reactor/requester.js +0 -22
  96. package/dist/src/graphql/reactor/requester.js.map +0 -1
  97. package/dist/src/graphql/reactor/requester.with-zod.d.ts +0 -4
  98. package/dist/src/graphql/reactor/requester.with-zod.d.ts.map +0 -1
  99. package/dist/src/graphql/reactor/requester.with-zod.js +0 -119
  100. package/dist/src/graphql/reactor/requester.with-zod.js.map +0 -1
  101. package/dist/src/graphql/reactor/resolvers.d.ts +0 -211
  102. package/dist/src/graphql/reactor/resolvers.d.ts.map +0 -1
  103. package/dist/src/graphql/reactor/resolvers.js +0 -595
  104. package/dist/src/graphql/reactor/resolvers.js.map +0 -1
  105. package/dist/src/graphql/reactor/schema.graphql +0 -469
  106. package/dist/src/graphql/reactor/subgraph.d.ts +0 -47
  107. package/dist/src/graphql/reactor/subgraph.d.ts.map +0 -1
  108. package/dist/src/graphql/reactor/subgraph.js +0 -522
  109. package/dist/src/graphql/reactor/subgraph.js.map +0 -1
  110. package/dist/src/graphql/reactor/validation.d.ts +0 -120
  111. package/dist/src/graphql/reactor/validation.d.ts.map +0 -1
  112. package/dist/src/graphql/reactor/validation.js +0 -87
  113. package/dist/src/graphql/reactor/validation.js.map +0 -1
  114. package/dist/src/graphql/system/env/getters.d.ts +0 -2
  115. package/dist/src/graphql/system/env/getters.d.ts.map +0 -1
  116. package/dist/src/graphql/system/env/getters.js +0 -4
  117. package/dist/src/graphql/system/env/getters.js.map +0 -1
  118. package/dist/src/graphql/system/env/index.d.ts +0 -2
  119. package/dist/src/graphql/system/env/index.d.ts.map +0 -1
  120. package/dist/src/graphql/system/env/index.js +0 -5
  121. package/dist/src/graphql/system/env/index.js.map +0 -1
  122. package/dist/src/graphql/system/index.d.ts +0 -2
  123. package/dist/src/graphql/system/index.d.ts.map +0 -1
  124. package/dist/src/graphql/system/index.js +0 -2
  125. package/dist/src/graphql/system/index.js.map +0 -1
  126. package/dist/src/graphql/system/types.d.ts +0 -2
  127. package/dist/src/graphql/system/types.d.ts.map +0 -1
  128. package/dist/src/graphql/system/types.js +0 -2
  129. package/dist/src/graphql/system/types.js.map +0 -1
  130. package/dist/src/graphql/temp-hack-rwa-type-defs.d.ts +0 -57
  131. package/dist/src/graphql/temp-hack-rwa-type-defs.d.ts.map +0 -1
  132. package/dist/src/graphql/temp-hack-rwa-type-defs.js +0 -2
  133. package/dist/src/graphql/temp-hack-rwa-type-defs.js.map +0 -1
  134. package/dist/src/graphql/types.d.ts +0 -103
  135. package/dist/src/graphql/types.d.ts.map +0 -1
  136. package/dist/src/graphql/types.js +0 -2
  137. package/dist/src/graphql/types.js.map +0 -1
  138. package/dist/src/graphql/utils.d.ts +0 -26
  139. package/dist/src/graphql/utils.d.ts.map +0 -1
  140. package/dist/src/graphql/utils.js +0 -104
  141. package/dist/src/graphql/utils.js.map +0 -1
  142. package/dist/src/graphql/websocket.d.ts +0 -3
  143. package/dist/src/graphql/websocket.d.ts.map +0 -1
  144. package/dist/src/graphql/websocket.js +0 -15
  145. package/dist/src/graphql/websocket.js.map +0 -1
  146. package/dist/src/migrations/001_create_document_permissions.d.ts +0 -4
  147. package/dist/src/migrations/001_create_document_permissions.d.ts.map +0 -1
  148. package/dist/src/migrations/001_create_document_permissions.js +0 -91
  149. package/dist/src/migrations/001_create_document_permissions.js.map +0 -1
  150. package/dist/src/migrations/index.d.ts +0 -10
  151. package/dist/src/migrations/index.d.ts.map +0 -1
  152. package/dist/src/migrations/index.js +0 -56
  153. package/dist/src/migrations/index.js.map +0 -1
  154. package/dist/src/packages/import-loader.d.ts +0 -16
  155. package/dist/src/packages/import-loader.d.ts.map +0 -1
  156. package/dist/src/packages/import-loader.js +0 -61
  157. package/dist/src/packages/import-loader.js.map +0 -1
  158. package/dist/src/packages/import-resolver.d.ts +0 -5
  159. package/dist/src/packages/import-resolver.d.ts.map +0 -1
  160. package/dist/src/packages/import-resolver.js +0 -127
  161. package/dist/src/packages/import-resolver.js.map +0 -1
  162. package/dist/src/packages/package-manager.d.ts +0 -34
  163. package/dist/src/packages/package-manager.d.ts.map +0 -1
  164. package/dist/src/packages/package-manager.js +0 -213
  165. package/dist/src/packages/package-manager.js.map +0 -1
  166. package/dist/src/packages/types.d.ts +0 -40
  167. package/dist/src/packages/types.d.ts.map +0 -1
  168. package/dist/src/packages/types.js +0 -2
  169. package/dist/src/packages/types.js.map +0 -1
  170. package/dist/src/packages/util.d.ts +0 -27
  171. package/dist/src/packages/util.d.ts.map +0 -1
  172. package/dist/src/packages/util.js +0 -97
  173. package/dist/src/packages/util.js.map +0 -1
  174. package/dist/src/packages/vite-loader.d.ts +0 -25
  175. package/dist/src/packages/vite-loader.d.ts.map +0 -1
  176. package/dist/src/packages/vite-loader.js +0 -182
  177. package/dist/src/packages/vite-loader.js.map +0 -1
  178. package/dist/src/server.d.ts +0 -80
  179. package/dist/src/server.d.ts.map +0 -1
  180. package/dist/src/server.js +0 -427
  181. package/dist/src/server.js.map +0 -1
  182. package/dist/src/services/auth.service.d.ts +0 -68
  183. package/dist/src/services/auth.service.d.ts.map +0 -1
  184. package/dist/src/services/auth.service.js +0 -190
  185. package/dist/src/services/auth.service.js.map +0 -1
  186. package/dist/src/services/document-permission.service.d.ts +0 -201
  187. package/dist/src/services/document-permission.service.d.ts.map +0 -1
  188. package/dist/src/services/document-permission.service.js +0 -636
  189. package/dist/src/services/document-permission.service.js.map +0 -1
  190. package/dist/src/sync/types.d.ts +0 -10
  191. package/dist/src/sync/types.d.ts.map +0 -1
  192. package/dist/src/sync/types.js +0 -2
  193. package/dist/src/sync/types.js.map +0 -1
  194. package/dist/src/sync/utils.d.ts +0 -7
  195. package/dist/src/sync/utils.d.ts.map +0 -1
  196. package/dist/src/sync/utils.js +0 -78
  197. package/dist/src/sync/utils.js.map +0 -1
  198. package/dist/src/tracing.d.ts +0 -4
  199. package/dist/src/tracing.d.ts.map +0 -1
  200. package/dist/src/tracing.js +0 -122
  201. package/dist/src/tracing.js.map +0 -1
  202. package/dist/src/types.d.ts +0 -18
  203. package/dist/src/types.d.ts.map +0 -1
  204. package/dist/src/types.js +0 -2
  205. package/dist/src/types.js.map +0 -1
  206. package/dist/src/utils/auth.d.ts +0 -3
  207. package/dist/src/utils/auth.d.ts.map +0 -1
  208. package/dist/src/utils/auth.js +0 -19
  209. package/dist/src/utils/auth.js.map +0 -1
  210. package/dist/src/utils/create-schema.d.ts +0 -31
  211. package/dist/src/utils/create-schema.d.ts.map +0 -1
  212. package/dist/src/utils/create-schema.js +0 -548
  213. package/dist/src/utils/create-schema.js.map +0 -1
  214. package/dist/src/utils/db.d.ts +0 -74
  215. package/dist/src/utils/db.d.ts.map +0 -1
  216. package/dist/src/utils/db.js +0 -101
  217. package/dist/src/utils/db.js.map +0 -1
  218. package/dist/src/utils/drive-url.d.ts +0 -2
  219. package/dist/src/utils/drive-url.d.ts.map +0 -1
  220. package/dist/src/utils/drive-url.js +0 -3
  221. package/dist/src/utils/drive-url.js.map +0 -1
  222. package/dist/src/utils/index.d.ts +0 -4
  223. package/dist/src/utils/index.d.ts.map +0 -1
  224. package/dist/src/utils/index.js +0 -4
  225. package/dist/src/utils/index.js.map +0 -1
  226. package/dist/test/benchmarks/load.bench.d.ts +0 -2
  227. package/dist/test/benchmarks/load.bench.d.ts.map +0 -1
  228. package/dist/test/benchmarks/load.bench.js +0 -73
  229. package/dist/test/benchmarks/load.bench.js.map +0 -1
  230. package/dist/test/benchmarks/sync.bench.d.ts +0 -2
  231. package/dist/test/benchmarks/sync.bench.d.ts.map +0 -1
  232. package/dist/test/benchmarks/sync.bench.js +0 -119
  233. package/dist/test/benchmarks/sync.bench.js.map +0 -1
  234. package/dist/test/connect-switchboard-reshuffle-convergence.test.d.ts +0 -2
  235. package/dist/test/connect-switchboard-reshuffle-convergence.test.d.ts.map +0 -1
  236. package/dist/test/connect-switchboard-reshuffle-convergence.test.js +0 -203
  237. package/dist/test/connect-switchboard-reshuffle-convergence.test.js.map +0 -1
  238. package/dist/test/connect-switchboard-sync.test.d.ts +0 -2
  239. package/dist/test/connect-switchboard-sync.test.d.ts.map +0 -1
  240. package/dist/test/connect-switchboard-sync.test.js +0 -581
  241. package/dist/test/connect-switchboard-sync.test.js.map +0 -1
  242. package/dist/test/document-drive-subgraph.test.d.ts +0 -2
  243. package/dist/test/document-drive-subgraph.test.d.ts.map +0 -1
  244. package/dist/test/document-drive-subgraph.test.js +0 -186
  245. package/dist/test/document-drive-subgraph.test.js.map +0 -1
  246. package/dist/test/document-model-subgraph-legacy-permissions.test.d.ts +0 -2
  247. package/dist/test/document-model-subgraph-legacy-permissions.test.d.ts.map +0 -1
  248. package/dist/test/document-model-subgraph-legacy-permissions.test.js +0 -518
  249. package/dist/test/document-model-subgraph-legacy-permissions.test.js.map +0 -1
  250. package/dist/test/document-model-subgraph-permissions.test.d.ts +0 -2
  251. package/dist/test/document-model-subgraph-permissions.test.d.ts.map +0 -1
  252. package/dist/test/document-model-subgraph-permissions.test.js +0 -635
  253. package/dist/test/document-model-subgraph-permissions.test.js.map +0 -1
  254. package/dist/test/document-model-subgraph.test.d.ts +0 -2
  255. package/dist/test/document-model-subgraph.test.d.ts.map +0 -1
  256. package/dist/test/document-model-subgraph.test.js +0 -441
  257. package/dist/test/document-model-subgraph.test.js.map +0 -1
  258. package/dist/test/document-permission.service.test.d.ts +0 -2
  259. package/dist/test/document-permission.service.test.d.ts.map +0 -1
  260. package/dist/test/document-permission.service.test.js +0 -480
  261. package/dist/test/document-permission.service.test.js.map +0 -1
  262. package/dist/test/drive-handlers.d.ts +0 -4
  263. package/dist/test/drive-handlers.d.ts.map +0 -1
  264. package/dist/test/drive-handlers.js +0 -39
  265. package/dist/test/drive-handlers.js.map +0 -1
  266. package/dist/test/drive-info-endpoint.test.d.ts +0 -2
  267. package/dist/test/drive-info-endpoint.test.d.ts.map +0 -1
  268. package/dist/test/drive-info-endpoint.test.js +0 -123
  269. package/dist/test/drive-info-endpoint.test.js.map +0 -1
  270. package/dist/test/drive-subgraph-permissions.test.d.ts +0 -2
  271. package/dist/test/drive-subgraph-permissions.test.d.ts.map +0 -1
  272. package/dist/test/drive-subgraph-permissions.test.js +0 -195
  273. package/dist/test/drive-subgraph-permissions.test.js.map +0 -1
  274. package/dist/test/drive.test.d.ts +0 -2
  275. package/dist/test/drive.test.d.ts.map +0 -1
  276. package/dist/test/drive.test.js +0 -142
  277. package/dist/test/drive.test.js.map +0 -1
  278. package/dist/test/identity-integration.test.d.ts +0 -2
  279. package/dist/test/identity-integration.test.d.ts.map +0 -1
  280. package/dist/test/identity-integration.test.js +0 -349
  281. package/dist/test/identity-integration.test.js.map +0 -1
  282. package/dist/test/index.d.ts +0 -3
  283. package/dist/test/index.d.ts.map +0 -1
  284. package/dist/test/index.js +0 -3
  285. package/dist/test/index.js.map +0 -1
  286. package/dist/test/permissions-integration.test.d.ts +0 -2
  287. package/dist/test/permissions-integration.test.d.ts.map +0 -1
  288. package/dist/test/permissions-integration.test.js +0 -421
  289. package/dist/test/permissions-integration.test.js.map +0 -1
  290. package/dist/test/pull-responder-transmitter.test.d.ts +0 -2
  291. package/dist/test/pull-responder-transmitter.test.d.ts.map +0 -1
  292. package/dist/test/pull-responder-transmitter.test.js +0 -220
  293. package/dist/test/pull-responder-transmitter.test.js.map +0 -1
  294. package/dist/test/push-backfill.test.d.ts +0 -2
  295. package/dist/test/push-backfill.test.d.ts.map +0 -1
  296. package/dist/test/push-backfill.test.js +0 -298
  297. package/dist/test/push-backfill.test.js.map +0 -1
  298. package/dist/test/push-transmitter.test.d.ts +0 -2
  299. package/dist/test/push-transmitter.test.d.ts.map +0 -1
  300. package/dist/test/push-transmitter.test.js +0 -179
  301. package/dist/test/push-transmitter.test.js.map +0 -1
  302. package/dist/test/reactor-adapters.test.d.ts +0 -2
  303. package/dist/test/reactor-adapters.test.d.ts.map +0 -1
  304. package/dist/test/reactor-adapters.test.js +0 -379
  305. package/dist/test/reactor-adapters.test.js.map +0 -1
  306. package/dist/test/reactor-client.test.d.ts +0 -2
  307. package/dist/test/reactor-client.test.d.ts.map +0 -1
  308. package/dist/test/reactor-client.test.js +0 -212
  309. package/dist/test/reactor-client.test.js.map +0 -1
  310. package/dist/test/reactor-resolvers.test.d.ts +0 -2
  311. package/dist/test/reactor-resolvers.test.d.ts.map +0 -1
  312. package/dist/test/reactor-resolvers.test.js +0 -258
  313. package/dist/test/reactor-resolvers.test.js.map +0 -1
  314. package/dist/test/reactor-subgraph-permissions.test.d.ts +0 -2
  315. package/dist/test/reactor-subgraph-permissions.test.d.ts.map +0 -1
  316. package/dist/test/reactor-subgraph-permissions.test.js +0 -397
  317. package/dist/test/reactor-subgraph-permissions.test.js.map +0 -1
  318. package/dist/test/router.test.d.ts +0 -2
  319. package/dist/test/router.test.d.ts.map +0 -1
  320. package/dist/test/router.test.js +0 -38
  321. package/dist/test/router.test.js.map +0 -1
  322. package/dist/test/subscriptions.test.d.ts +0 -2
  323. package/dist/test/subscriptions.test.d.ts.map +0 -1
  324. package/dist/test/subscriptions.test.js +0 -248
  325. package/dist/test/subscriptions.test.js.map +0 -1
  326. package/dist/test/utils/gql-resolver-bridge.d.ts +0 -15
  327. package/dist/test/utils/gql-resolver-bridge.d.ts.map +0 -1
  328. package/dist/test/utils/gql-resolver-bridge.js +0 -89
  329. package/dist/test/utils/gql-resolver-bridge.js.map +0 -1
  330. package/dist/test/utils.d.ts +0 -10
  331. package/dist/test/utils.d.ts.map +0 -1
  332. package/dist/test/utils.js +0 -23
  333. package/dist/test/utils.js.map +0 -1
  334. package/dist/tsconfig.tsbuildinfo +0 -1
  335. package/dist/vitest.config.d.ts +0 -3
  336. package/dist/vitest.config.d.ts.map +0 -1
  337. package/dist/vitest.config.js +0 -38
  338. package/dist/vitest.config.js.map +0 -1
@@ -1,635 +0,0 @@
1
- import { GraphQLError } from "graphql";
2
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
- import { DocumentModelSubgraph } from "../src/graphql/document-model-subgraph.js";
4
- describe("DocumentModelSubgraph Permission Checks", () => {
5
- let mockDocumentPermissionService;
6
- let mockReactor;
7
- let mockReactorClient;
8
- let subgraph;
9
- const mockDocumentModel = {
10
- documentModel: {
11
- global: {
12
- id: "powerhouse/test-model",
13
- name: "Test Model",
14
- specifications: [
15
- {
16
- version: 1,
17
- changeLog: [],
18
- modules: [
19
- {
20
- name: "Base",
21
- operations: [
22
- { name: "SET_NAME" },
23
- { name: "SET_VALUE" },
24
- { name: "RESTRICTED_OP" },
25
- ],
26
- },
27
- ],
28
- state: { global: {}, local: {} },
29
- },
30
- ],
31
- },
32
- },
33
- actions: {
34
- setName: vi.fn((input) => ({ type: "SET_NAME", input })),
35
- setValue: vi.fn((input) => ({ type: "SET_VALUE", input })),
36
- restrictedOp: vi.fn((input) => ({ type: "RESTRICTED_OP", input })),
37
- },
38
- reducer: vi.fn(),
39
- };
40
- const createMockDocument = (id, name) => ({
41
- header: {
42
- id,
43
- slug: id,
44
- name,
45
- documentType: "powerhouse/test-model",
46
- revision: { global: 1 },
47
- createdAtUtcIso: new Date().toISOString(),
48
- lastModifiedAtUtcIso: new Date().toISOString(),
49
- },
50
- state: {
51
- global: { name },
52
- local: {},
53
- },
54
- initialState: {
55
- global: { name },
56
- local: {},
57
- },
58
- operations: {
59
- global: [],
60
- local: [],
61
- },
62
- attachments: {},
63
- clipboard: [],
64
- });
65
- const mockDocument = createMockDocument("doc-123", "Test Document");
66
- const createContext = (options) => ({
67
- user: options.userAddress ? { address: options.userAddress } : undefined,
68
- isAdmin: vi.fn().mockReturnValue(options.isAdmin ?? false),
69
- isUser: vi.fn().mockReturnValue(options.isUser ?? false),
70
- isGuest: vi.fn().mockReturnValue(options.isGuest ?? false),
71
- });
72
- beforeEach(() => {
73
- vi.clearAllMocks();
74
- delete process.env.FREE_ENTRY;
75
- mockDocumentPermissionService = {
76
- canRead: vi.fn().mockResolvedValue(false),
77
- canWrite: vi.fn().mockResolvedValue(false),
78
- canReadDocument: vi.fn().mockResolvedValue(false),
79
- canWriteDocument: vi.fn().mockResolvedValue(false),
80
- isOperationRestricted: vi.fn().mockResolvedValue(false),
81
- canExecuteOperation: vi.fn().mockResolvedValue(false),
82
- };
83
- mockReactor = {
84
- getDocument: vi.fn().mockResolvedValue(mockDocument),
85
- getDocuments: vi.fn().mockResolvedValue(["doc-123"]),
86
- addDocument: vi.fn().mockResolvedValue(mockDocument),
87
- addAction: vi.fn().mockResolvedValue({
88
- status: "SUCCESS",
89
- operations: [{ index: 1 }],
90
- }),
91
- };
92
- mockReactorClient = {
93
- getParents: vi.fn().mockResolvedValue({
94
- results: [],
95
- options: { limit: 10, cursor: "" },
96
- }),
97
- getChildren: vi.fn().mockResolvedValue({
98
- results: [],
99
- options: { limit: 10, cursor: "" },
100
- }),
101
- get: vi.fn().mockResolvedValue(mockDocument),
102
- find: vi.fn().mockResolvedValue({
103
- results: [mockDocument],
104
- options: { limit: 10, cursor: "" },
105
- }),
106
- createEmpty: vi.fn().mockResolvedValue(mockDocument),
107
- execute: vi.fn().mockResolvedValue({
108
- ...mockDocument,
109
- header: { ...mockDocument.header, revision: { global: 2 } },
110
- }),
111
- };
112
- subgraph = new DocumentModelSubgraph(mockDocumentModel, {
113
- reactor: mockReactor,
114
- reactorClient: mockReactorClient,
115
- documentPermissionService: mockDocumentPermissionService,
116
- relationalDb: {},
117
- graphqlManager: {},
118
- syncManager: {},
119
- });
120
- });
121
- afterEach(() => {
122
- delete process.env.FREE_ENTRY;
123
- });
124
- describe("Query: document", () => {
125
- // Updated to match new flat resolver structure (TestModel_document instead of TestModel.getDocument)
126
- const callGetDocument = async (ctx, identifier) => {
127
- const queryResolver = subgraph.resolvers.Query
128
- ?.TestModel_document;
129
- return queryResolver(null, { identifier }, ctx);
130
- };
131
- describe("Global Role Access (hasGlobalReadAccess)", () => {
132
- it("should allow access when user is global admin", async () => {
133
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
134
- const result = await callGetDocument(ctx, "doc-123");
135
- // Result is DocumentWithChildren: { document: PHDocument, childIds: string[] }
136
- expect(result).toBeDefined();
137
- expect(result.document.id).toBe("doc-123");
138
- expect(mockDocumentPermissionService.canRead).not.toHaveBeenCalled();
139
- });
140
- it("should allow access when user is global user", async () => {
141
- const ctx = createContext({ isUser: true, userAddress: "0xuser" });
142
- const result = await callGetDocument(ctx, "doc-123");
143
- expect(result).toBeDefined();
144
- expect(mockDocumentPermissionService.canRead).not.toHaveBeenCalled();
145
- });
146
- it("should allow access when user is global guest", async () => {
147
- const ctx = createContext({ isGuest: true, userAddress: "0xguest" });
148
- const result = await callGetDocument(ctx, "doc-123");
149
- expect(result).toBeDefined();
150
- expect(mockDocumentPermissionService.canRead).not.toHaveBeenCalled();
151
- });
152
- it("should allow access when FREE_ENTRY is true", async () => {
153
- process.env.FREE_ENTRY = "true";
154
- const ctx = createContext({ userAddress: "0xanyone" });
155
- const result = await callGetDocument(ctx, "doc-123");
156
- expect(result).toBeDefined();
157
- expect(mockDocumentPermissionService.canRead).not.toHaveBeenCalled();
158
- });
159
- });
160
- describe("Document Permission Access", () => {
161
- it("should check document permissions when no global access", async () => {
162
- vi.mocked(mockDocumentPermissionService.canRead).mockResolvedValue(true);
163
- const ctx = createContext({ userAddress: "0xpermitted" });
164
- const result = await callGetDocument(ctx, "doc-123");
165
- expect(result).toBeDefined();
166
- expect(mockDocumentPermissionService.canRead).toHaveBeenCalledWith("doc-123", "0xpermitted", expect.any(Function));
167
- });
168
- it("should deny access when user has no permissions", async () => {
169
- vi.mocked(mockDocumentPermissionService.canRead).mockResolvedValue(false);
170
- const ctx = createContext({ userAddress: "0xunpermitted" });
171
- await expect(callGetDocument(ctx, "doc-123")).rejects.toThrow(GraphQLError);
172
- await expect(callGetDocument(ctx, "doc-123")).rejects.toThrow("Forbidden: insufficient permissions to read this document");
173
- });
174
- it("should deny access when user is not authenticated", async () => {
175
- const ctx = createContext({});
176
- await expect(callGetDocument(ctx, "doc-123")).rejects.toThrow("Forbidden");
177
- });
178
- });
179
- describe("Document validation", () => {
180
- it("should throw error when identifier is not provided", async () => {
181
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
182
- await expect(callGetDocument(ctx, "")).rejects.toThrow("Document identifier is required");
183
- });
184
- // Note: Drive validation is no longer part of document query in new API
185
- // Documents are retrieved directly by identifier, parentId filtering is done via findDocuments
186
- it.skip("should verify document is in specified drive when driveId provided", async () => {
187
- mockReactorClient.find = vi.fn().mockResolvedValue({
188
- results: [],
189
- options: { limit: 10, cursor: "" },
190
- });
191
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
192
- // This test is no longer applicable - drive filtering is done via findDocuments
193
- await expect(callGetDocument(ctx, "doc-123")).rejects.toThrow("is not part of");
194
- });
195
- it("should throw error if document type does not match", async () => {
196
- const wrongTypeDoc = {
197
- ...mockDocument,
198
- header: { ...mockDocument.header, documentType: "other/type" },
199
- };
200
- mockReactorClient.get = vi.fn().mockResolvedValue(wrongTypeDoc);
201
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
202
- await expect(callGetDocument(ctx, "doc-123")).rejects.toThrow("is not of type");
203
- });
204
- });
205
- describe("Permission inheritance (hierarchy)", () => {
206
- it("should pass getParentIdsFn that retrieves parent IDs", async () => {
207
- const mockParents = [
208
- createMockDocument("parent-1", "Parent 1"),
209
- createMockDocument("parent-2", "Parent 2"),
210
- ];
211
- vi.mocked(mockReactorClient.getParents).mockResolvedValue({
212
- results: mockParents,
213
- options: { limit: 10, cursor: "" },
214
- });
215
- let capturedGetParentsFn = null;
216
- vi.mocked(mockDocumentPermissionService.canRead).mockImplementation(async (_docId, _user, getParentsFn) => {
217
- capturedGetParentsFn = getParentsFn;
218
- return true;
219
- });
220
- const ctx = createContext({ userAddress: "0xuser" });
221
- await callGetDocument(ctx, "child-doc");
222
- expect(capturedGetParentsFn).not.toBeNull();
223
- const parentIds = await capturedGetParentsFn("child-doc");
224
- expect(parentIds).toEqual(["parent-1", "parent-2"]);
225
- });
226
- it("should return empty array if getParents fails", async () => {
227
- vi.mocked(mockReactorClient.getParents).mockRejectedValue(new Error("Not found"));
228
- let capturedGetParentsFn = null;
229
- vi.mocked(mockDocumentPermissionService.canRead).mockImplementation(async (_docId, _user, getParentsFn) => {
230
- capturedGetParentsFn = getParentsFn;
231
- return true;
232
- });
233
- const ctx = createContext({ userAddress: "0xuser" });
234
- await callGetDocument(ctx, "child-doc");
235
- const parentIds = await capturedGetParentsFn("child-doc");
236
- expect(parentIds).toEqual([]);
237
- });
238
- });
239
- describe("reactorClient integration", () => {
240
- // Note: Drive filtering is now done via findDocuments, not document query
241
- it.skip("should use reactorClient.find to check document in drive", async () => {
242
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
243
- await callGetDocument(ctx, "doc-123");
244
- // This test is no longer applicable - drive filtering is done via findDocuments
245
- expect(mockReactorClient.find).toHaveBeenCalledWith({
246
- parentId: "drive-1",
247
- ids: ["doc-123"],
248
- });
249
- });
250
- it("should use reactorClient.get to fetch document", async () => {
251
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
252
- await callGetDocument(ctx, "doc-123");
253
- // The shared resolver calls get with identifier and optional view
254
- expect(mockReactorClient.get).toHaveBeenCalledWith("doc-123", undefined);
255
- });
256
- });
257
- });
258
- describe("Query: findDocuments", () => {
259
- // Updated to match new flat resolver structure (TestModel_findDocuments)
260
- const callFindDocuments = async (ctx, parentId) => {
261
- const queryResolver = subgraph.resolvers.Query
262
- ?.TestModel_findDocuments;
263
- const result = await queryResolver(null, { search: { parentId }, paging: { limit: 10 } }, ctx);
264
- return result.items;
265
- };
266
- describe("Global Role Access", () => {
267
- it("should return all documents for admin", async () => {
268
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
269
- const result = await callFindDocuments(ctx, "drive-1");
270
- expect(result).toHaveLength(1);
271
- expect(mockDocumentPermissionService.canRead).not.toHaveBeenCalled();
272
- });
273
- it("should return all documents for user", async () => {
274
- const ctx = createContext({ isUser: true, userAddress: "0xuser" });
275
- const result = await callFindDocuments(ctx, "drive-1");
276
- expect(result).toHaveLength(1);
277
- });
278
- it("should return all documents for guest", async () => {
279
- const ctx = createContext({ isGuest: true, userAddress: "0xguest" });
280
- const result = await callFindDocuments(ctx, "drive-1");
281
- expect(result).toHaveLength(1);
282
- });
283
- });
284
- describe("Document Permission Filtering", () => {
285
- beforeEach(() => {
286
- const docs = [
287
- createMockDocument("doc-1", "Doc 1"),
288
- createMockDocument("doc-2", "Doc 2"),
289
- createMockDocument("doc-3", "Doc 3"),
290
- ];
291
- mockReactorClient.find = vi.fn().mockResolvedValue({
292
- results: docs,
293
- options: { limit: 10, cursor: "" },
294
- });
295
- });
296
- it("should filter documents based on permissions when no global access", async () => {
297
- vi.mocked(mockDocumentPermissionService.canRead).mockImplementation(async (docId) => docId === "drive-1" || docId === "doc-1" || docId === "doc-3");
298
- const ctx = createContext({ userAddress: "0xpartial" });
299
- const result = await callFindDocuments(ctx, "drive-1");
300
- expect(result).toHaveLength(2);
301
- expect(result.map((d) => d.id).sort()).toEqual(["doc-1", "doc-3"]);
302
- });
303
- it("should return empty array when user has no document permissions", async () => {
304
- vi.mocked(mockDocumentPermissionService.canRead).mockImplementation(async (docId) => docId === "drive-1");
305
- const ctx = createContext({ userAddress: "0xnopermissions" });
306
- const result = await callFindDocuments(ctx, "drive-1");
307
- expect(result).toHaveLength(0);
308
- });
309
- });
310
- describe("Permission filtering", () => {
311
- // Note: In the new API, findDocuments filters results based on individual document permissions
312
- // rather than checking drive permission first
313
- it("should filter documents when user has no global access", async () => {
314
- vi.mocked(mockDocumentPermissionService.canRead).mockResolvedValue(false);
315
- const ctx = createContext({ userAddress: "0xunpermitted" });
316
- // With no permissions, all documents should be filtered out
317
- const result = await callFindDocuments(ctx, "drive-1");
318
- expect(result).toHaveLength(0);
319
- });
320
- });
321
- describe("reactorClient integration", () => {
322
- it("should use reactorClient.find with type filter", async () => {
323
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
324
- await callFindDocuments(ctx, "drive-1");
325
- // The shared resolver now uses find with these parameters - first call includes type filter
326
- expect(mockReactorClient.find).toHaveBeenCalledWith(expect.objectContaining({
327
- type: "powerhouse/test-model",
328
- parentId: "drive-1",
329
- }), undefined, expect.objectContaining({
330
- limit: 10,
331
- }));
332
- });
333
- });
334
- });
335
- describe("Mutation: createDocument", () => {
336
- const callCreateDocument = async (ctx, name, parentIdentifier) => {
337
- const mutation = subgraph.resolvers.Mutation
338
- ?.TestModel_createDocument;
339
- return mutation(null, { name, parentIdentifier }, ctx);
340
- };
341
- describe("Global Role Access (hasGlobalWriteAccess)", () => {
342
- it("should allow creation when user is global admin", async () => {
343
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
344
- const result = await callCreateDocument(ctx, "New Doc");
345
- expect(result).toMatchObject({ id: "doc-123" });
346
- expect(mockDocumentPermissionService.canWrite).not.toHaveBeenCalled();
347
- });
348
- it("should allow creation when user is global user", async () => {
349
- const ctx = createContext({ isUser: true, userAddress: "0xuser" });
350
- const result = await callCreateDocument(ctx, "New Doc");
351
- expect(result).toMatchObject({ id: "doc-123" });
352
- });
353
- it("should deny creation when user is only global guest", async () => {
354
- const ctx = createContext({ isGuest: true, userAddress: "0xguest" });
355
- await expect(callCreateDocument(ctx, "New Doc")).rejects.toThrow("Forbidden: insufficient permissions to create documents");
356
- });
357
- });
358
- describe("With parentIdentifier", () => {
359
- it("should check write permission on parent when parentIdentifier provided", async () => {
360
- vi.mocked(mockDocumentPermissionService.canWrite).mockResolvedValue(true);
361
- const ctx = createContext({ userAddress: "0xpermitted" });
362
- const result = await callCreateDocument(ctx, "New Doc", "drive-1");
363
- expect(result).toMatchObject({ id: "doc-123" });
364
- expect(mockDocumentPermissionService.canWrite).toHaveBeenCalledWith("drive-1", "0xpermitted", expect.any(Function));
365
- });
366
- it("should deny creation when user cannot write to parent", async () => {
367
- vi.mocked(mockDocumentPermissionService.canWrite).mockResolvedValue(false);
368
- const ctx = createContext({ userAddress: "0xunpermitted" });
369
- await expect(callCreateDocument(ctx, "New Doc", "drive-1")).rejects.toThrow("Forbidden");
370
- });
371
- });
372
- describe("Without parentIdentifier", () => {
373
- it("should check global write access when no parentIdentifier", async () => {
374
- const ctx = createContext({ userAddress: "0xnoglobal" });
375
- await expect(callCreateDocument(ctx, "New Doc")).rejects.toThrow("Forbidden: insufficient permissions to create documents");
376
- });
377
- });
378
- describe("reactorClient integration", () => {
379
- it("should use reactorClient.createEmpty with parentIdentifier", async () => {
380
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
381
- await callCreateDocument(ctx, "New Doc", "drive-1");
382
- expect(mockReactorClient.createEmpty).toHaveBeenCalledWith("powerhouse/test-model", { parentIdentifier: "drive-1" });
383
- });
384
- it("should use reactorClient.execute to set name", async () => {
385
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
386
- await callCreateDocument(ctx, "New Doc");
387
- expect(mockReactorClient.execute).toHaveBeenCalledWith("doc-123", "main", [expect.objectContaining({ type: "SET_NAME" })]);
388
- });
389
- it("should not call execute if name is empty", async () => {
390
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
391
- await callCreateDocument(ctx, "");
392
- expect(mockReactorClient.createEmpty).toHaveBeenCalled();
393
- expect(mockReactorClient.execute).not.toHaveBeenCalled();
394
- });
395
- });
396
- });
397
- describe("Mutation: operations (setName, setValue, etc.)", () => {
398
- const callMutation = async (ctx, operationName, docId, input) => {
399
- const mutation = subgraph.resolvers.Mutation?.[`TestModel_${operationName}`];
400
- return mutation(null, { docId, input }, ctx);
401
- };
402
- describe("Write Permission Check", () => {
403
- it("should check write permission before executing operation", async () => {
404
- vi.mocked(mockDocumentPermissionService.canWrite).mockResolvedValue(true);
405
- const ctx = createContext({ userAddress: "0xpermitted" });
406
- await callMutation(ctx, "setName", "doc-123", { name: "New Name" });
407
- expect(mockDocumentPermissionService.canWrite).toHaveBeenCalledWith("doc-123", "0xpermitted", expect.any(Function));
408
- });
409
- it("should deny operation when user cannot write", async () => {
410
- vi.mocked(mockDocumentPermissionService.canWrite).mockResolvedValue(false);
411
- const ctx = createContext({ userAddress: "0xunpermitted" });
412
- await expect(callMutation(ctx, "setName", "doc-123", { name: "New Name" })).rejects.toThrow("Forbidden: insufficient permissions to write");
413
- });
414
- it("should allow operation for global admin without permission check", async () => {
415
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
416
- const result = await callMutation(ctx, "setName", "doc-123", {
417
- name: "New Name",
418
- });
419
- expect(result).toMatchObject({
420
- id: "doc-123",
421
- revisionsList: expect.arrayContaining([
422
- expect.objectContaining({ scope: "global", revision: 2 }),
423
- ]),
424
- });
425
- expect(mockDocumentPermissionService.canWrite).not.toHaveBeenCalled();
426
- });
427
- it("should allow operation for global user without permission check", async () => {
428
- const ctx = createContext({ isUser: true, userAddress: "0xuser" });
429
- const result = await callMutation(ctx, "setName", "doc-123", {
430
- name: "New Name",
431
- });
432
- expect(result).toMatchObject({
433
- id: "doc-123",
434
- revisionsList: expect.arrayContaining([
435
- expect.objectContaining({ scope: "global", revision: 2 }),
436
- ]),
437
- });
438
- });
439
- });
440
- describe("Operation-Level Permission Check", () => {
441
- it("should check operation restriction after write permission", async () => {
442
- vi.mocked(mockDocumentPermissionService.canWrite).mockResolvedValue(true);
443
- vi.mocked(mockDocumentPermissionService.isOperationRestricted).mockResolvedValue(false);
444
- const ctx = createContext({ userAddress: "0xpermitted" });
445
- await callMutation(ctx, "setName", "doc-123", { name: "New Name" });
446
- expect(mockDocumentPermissionService.isOperationRestricted).toHaveBeenCalledWith("doc-123", "SET_NAME");
447
- });
448
- it("should allow operation when not restricted", async () => {
449
- vi.mocked(mockDocumentPermissionService.canWrite).mockResolvedValue(true);
450
- vi.mocked(mockDocumentPermissionService.isOperationRestricted).mockResolvedValue(false);
451
- const ctx = createContext({ userAddress: "0xpermitted" });
452
- const result = await callMutation(ctx, "setName", "doc-123", {
453
- name: "New Name",
454
- });
455
- expect(result).toMatchObject({
456
- id: "doc-123",
457
- revisionsList: expect.arrayContaining([
458
- expect.objectContaining({ scope: "global", revision: 2 }),
459
- ]),
460
- });
461
- expect(mockDocumentPermissionService.canExecuteOperation).not.toHaveBeenCalled();
462
- });
463
- it("should check operation permission when operation is restricted", async () => {
464
- vi.mocked(mockDocumentPermissionService.canWrite).mockResolvedValue(true);
465
- vi.mocked(mockDocumentPermissionService.isOperationRestricted).mockResolvedValue(true);
466
- vi.mocked(mockDocumentPermissionService.canExecuteOperation).mockResolvedValue(true);
467
- const ctx = createContext({ userAddress: "0xauthorized" });
468
- const result = await callMutation(ctx, "restrictedOp", "doc-123", {
469
- value: 42,
470
- });
471
- expect(result).toMatchObject({
472
- id: "doc-123",
473
- revisionsList: expect.arrayContaining([
474
- expect.objectContaining({ scope: "global", revision: 2 }),
475
- ]),
476
- });
477
- expect(mockDocumentPermissionService.canExecuteOperation).toHaveBeenCalledWith("doc-123", "RESTRICTED_OP", "0xauthorized");
478
- });
479
- it("should deny operation when user lacks operation permission", async () => {
480
- vi.mocked(mockDocumentPermissionService.canWrite).mockResolvedValue(true);
481
- vi.mocked(mockDocumentPermissionService.isOperationRestricted).mockResolvedValue(true);
482
- vi.mocked(mockDocumentPermissionService.canExecuteOperation).mockResolvedValue(false);
483
- const ctx = createContext({ userAddress: "0xunauthorized" });
484
- await expect(callMutation(ctx, "restrictedOp", "doc-123", { value: 42 })).rejects.toThrow('Forbidden: insufficient permissions to execute operation "RESTRICTED_OP"');
485
- });
486
- it("should skip operation restriction check for global admin", async () => {
487
- vi.mocked(mockDocumentPermissionService.isOperationRestricted).mockResolvedValue(true);
488
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
489
- await callMutation(ctx, "restrictedOp", "doc-123", { value: 42 });
490
- expect(mockDocumentPermissionService.isOperationRestricted).not.toHaveBeenCalled();
491
- });
492
- });
493
- describe("Document type validation", () => {
494
- it("should throw error when document type does not match", async () => {
495
- vi.mocked(mockDocumentPermissionService.canWrite).mockResolvedValue(true);
496
- const wrongTypeDoc = {
497
- ...mockDocument,
498
- header: { ...mockDocument.header, documentType: "other/type" },
499
- };
500
- mockReactorClient.get = vi.fn().mockResolvedValue(wrongTypeDoc);
501
- const ctx = createContext({ userAddress: "0xpermitted" });
502
- await expect(callMutation(ctx, "setName", "doc-123", { name: "New Name" })).rejects.toThrow("is not of type");
503
- });
504
- });
505
- describe("reactorClient integration", () => {
506
- it("should use reactorClient.get to verify document", async () => {
507
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
508
- await callMutation(ctx, "setName", "doc-123", { name: "New Name" });
509
- expect(mockReactorClient.get).toHaveBeenCalledWith("doc-123");
510
- });
511
- it("should use reactorClient.execute to apply action", async () => {
512
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
513
- await callMutation(ctx, "setName", "doc-123", { name: "New Name" });
514
- expect(mockReactorClient.execute).toHaveBeenCalledWith("doc-123", "main", [expect.objectContaining({ type: "SET_NAME" })]);
515
- });
516
- it("should return PHDocument from updated document", async () => {
517
- mockReactorClient.execute = vi.fn().mockResolvedValue({
518
- ...mockDocument,
519
- header: { ...mockDocument.header, revision: { global: 42 } },
520
- });
521
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
522
- const result = await callMutation(ctx, "setName", "doc-123", {
523
- name: "New Name",
524
- });
525
- expect(result).toMatchObject({
526
- id: "doc-123",
527
- revisionsList: expect.arrayContaining([
528
- expect.objectContaining({ scope: "global", revision: 42 }),
529
- ]),
530
- });
531
- });
532
- it("should handle execute errors gracefully", async () => {
533
- mockReactorClient.execute = vi
534
- .fn()
535
- .mockRejectedValue(new Error("Execute failed"));
536
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
537
- await expect(callMutation(ctx, "setName", "doc-123", { name: "New Name" })).rejects.toThrow("Execute failed");
538
- });
539
- });
540
- });
541
- describe("AUTH_ENABLED=false behavior", () => {
542
- it("should allow all read access when all roles return true", async () => {
543
- const ctx = createContext({
544
- isAdmin: true,
545
- isUser: true,
546
- isGuest: true,
547
- userAddress: "0xanyone",
548
- });
549
- const queryResolver = subgraph.resolvers.Query
550
- ?.TestModel_document;
551
- const result = await queryResolver(null, { identifier: "doc-123" }, ctx);
552
- expect(result).toBeDefined();
553
- expect(mockDocumentPermissionService.canRead).not.toHaveBeenCalled();
554
- });
555
- it("should allow all write access when admin/user roles return true", async () => {
556
- const ctx = createContext({
557
- isAdmin: true,
558
- isUser: true,
559
- isGuest: true,
560
- userAddress: "0xanyone",
561
- });
562
- const result = await subgraph.resolvers.Mutation?.TestModel_setName(null, { docId: "doc-123", input: { name: "New" } }, ctx);
563
- expect(result).toMatchObject({
564
- id: "doc-123",
565
- revisionsList: expect.arrayContaining([
566
- expect.objectContaining({ scope: "global", revision: 2 }),
567
- ]),
568
- });
569
- expect(mockDocumentPermissionService.canWrite).not.toHaveBeenCalled();
570
- });
571
- });
572
- describe("No Permission Service", () => {
573
- let subgraphWithoutPermService;
574
- beforeEach(() => {
575
- subgraphWithoutPermService = new DocumentModelSubgraph(mockDocumentModel, {
576
- reactor: mockReactor,
577
- reactorClient: mockReactorClient,
578
- documentPermissionService: undefined,
579
- relationalDb: {},
580
- graphqlManager: {},
581
- syncManager: {},
582
- });
583
- });
584
- it("should deny read access when no permission service and no global access", async () => {
585
- const ctx = createContext({ userAddress: "0xuser" });
586
- const queryResolver = subgraphWithoutPermService.resolvers.Query
587
- ?.TestModel_document;
588
- await expect(queryResolver(null, { identifier: "doc-123" }, ctx)).rejects.toThrow("Forbidden");
589
- });
590
- it("should deny write access when no permission service and no global access", async () => {
591
- const ctx = createContext({ userAddress: "0xuser" });
592
- await expect(subgraphWithoutPermService.resolvers.Mutation?.TestModel_setName(null, { docId: "doc-123", input: { name: "New" } }, ctx)).rejects.toThrow("Forbidden");
593
- });
594
- it("should allow access with global roles even without permission service", async () => {
595
- const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
596
- const queryResolver = subgraphWithoutPermService.resolvers.Query
597
- ?.TestModel_document;
598
- const result = await queryResolver(null, { identifier: "doc-123" }, ctx);
599
- expect(result).toBeDefined();
600
- });
601
- it("should skip operation restriction check when no permission service", async () => {
602
- const ctx = createContext({ isUser: true, userAddress: "0xuser" });
603
- const result = await subgraphWithoutPermService.resolvers.Mutation?.TestModel_setName(null, { docId: "doc-123", input: { name: "New" } }, ctx);
604
- expect(result).toMatchObject({
605
- id: "doc-123",
606
- revisionsList: expect.arrayContaining([
607
- expect.objectContaining({ scope: "global", revision: 2 }),
608
- ]),
609
- });
610
- });
611
- });
612
- describe("Edge Cases", () => {
613
- it("should handle empty user address in context", async () => {
614
- const ctx = {
615
- user: { address: "" },
616
- isAdmin: vi.fn().mockReturnValue(false),
617
- isUser: vi.fn().mockReturnValue(false),
618
- isGuest: vi.fn().mockReturnValue(false),
619
- };
620
- const queryResolver = subgraph.resolvers.Query
621
- ?.TestModel_document;
622
- await expect(queryResolver(null, { identifier: "doc-123" }, ctx)).rejects.toThrow("Forbidden");
623
- expect(ctx.isAdmin).toHaveBeenCalledWith("");
624
- });
625
- it("should pass correct operation type name to permission check", async () => {
626
- vi.mocked(mockDocumentPermissionService.canWrite).mockResolvedValue(true);
627
- vi.mocked(mockDocumentPermissionService.isOperationRestricted).mockResolvedValue(true);
628
- vi.mocked(mockDocumentPermissionService.canExecuteOperation).mockResolvedValue(true);
629
- const ctx = createContext({ userAddress: "0xuser" });
630
- await subgraph.resolvers.Mutation?.TestModel_setValue(null, { docId: "doc-123", input: { value: 42 } }, ctx);
631
- expect(mockDocumentPermissionService.isOperationRestricted).toHaveBeenCalledWith("doc-123", "SET_VALUE");
632
- });
633
- });
634
- });
635
- //# sourceMappingURL=document-model-subgraph-permissions.test.js.map