@reventlessdev/reventless-aws 3.0.0-alpha.344 → 3.0.0-alpha.346

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 (263) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/package.json +15 -12
  3. package/run-provision-accounts.mjs +3 -0
  4. package/run-provision-admin.mjs +3 -0
  5. package/scripts/ProvisionAccounts.res +325 -0
  6. package/scripts/ProvisionAccounts.res.mjs +337 -0
  7. package/scripts/ProvisionAdmin.res +275 -0
  8. package/scripts/ProvisionAdmin.res.mjs +289 -0
  9. package/scripts/ProvisionCognito.res +149 -0
  10. package/scripts/ProvisionCognito.res.mjs +98 -0
  11. package/scripts/ProvisionIdentity.res +84 -14
  12. package/scripts/ProvisionIdentity.res.mjs +72 -7
  13. package/scripts/ProvisionProvider.res +104 -0
  14. package/scripts/ProvisionProvider.res.mjs +123 -0
  15. package/src/Platform.res +358 -329
  16. package/src/Platform.res.mjs +24 -12
  17. package/src/Platform_Casts.res +13 -4
  18. package/src/Platform_Stack.res +119 -9
  19. package/src/Platform_Stack.res.mjs +42 -4
  20. package/src/adapter/Api/AppSyncEventsSigner_Ops.res +8 -4
  21. package/src/adapter/Api/AppSync_EventsApi.res +12 -14
  22. package/src/adapter/Api/AppSync_Resolver_Native.res +3 -4
  23. package/src/adapter/Api/AppSync_Resolver_Retrying.res +78 -70
  24. package/src/adapter/Api/AppSync_SourceApiAssociation_Retrying.res +11 -8
  25. package/src/adapter/Api/Platform_AdminScan_Ops.res +15 -14
  26. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +10 -2
  27. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +40 -50
  28. package/src/adapter/Api/Platform_UIFragments_Lambda.res +39 -32
  29. package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res +5 -2
  30. package/src/adapter/Auth/Auth_ActiveRolePoolAttachment.res +0 -1
  31. package/src/adapter/Auth/Auth_ActiveRoleStore.res +1 -2
  32. package/src/adapter/Auth/Auth_ActiveRoleStore_Schema.res +1 -4
  33. package/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res +5 -2
  34. package/src/adapter/Auth/Auth_Cognito.res +3 -9
  35. package/src/adapter/Auth/Auth_LoginIdentifier.res +66 -0
  36. package/src/adapter/Auth/Auth_LoginIdentifier.res.mjs +70 -0
  37. package/src/adapter/Auth/Auth_SignUpMode.res +78 -0
  38. package/src/adapter/Auth/Auth_SignUpMode.res.mjs +56 -0
  39. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res +1 -4
  40. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_NoOp.res +3 -1
  41. package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res +1 -4
  42. package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res +7 -4
  43. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res +6 -1
  44. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res +7 -4
  45. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res +24 -18
  46. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res +9 -4
  47. package/src/adapter/CommandTopic/CommandTopicRegistry.res +1 -4
  48. package/src/adapter/Counter/CounterHandler_DynamoDbStream.res +15 -15
  49. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res +9 -5
  50. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +179 -213
  51. package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res +5 -5
  52. package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res +6 -2
  53. package/src/adapter/EventCollector/EventCollectorChannel_SQS.res +14 -7
  54. package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res +14 -7
  55. package/src/adapter/EventCollector/EventCollectorChannel_SQS_Runtime.res +6 -3
  56. package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res +6 -1
  57. package/src/adapter/EventLog/EventLogStorage_DynamoDb_Runtime.res +13 -17
  58. package/src/adapter/EventLog/EventLogStorage_Postgres.res +7 -4
  59. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +12 -7
  60. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res +4 -2
  61. package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res +3 -2
  62. package/src/adapter/EventTopic/EventTopicPublisher_SNS.res +20 -12
  63. package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res +21 -9
  64. package/src/adapter/EventTopic/EventTopicPublisher_SNS_Runtime.res +5 -3
  65. package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res +6 -3
  66. package/src/adapter/Mcp/MCP_Lambda.res +31 -46
  67. package/src/adapter/Messaging/Messaging_Ses_Backend.res +11 -7
  68. package/src/adapter/Messaging/Messaging_Ses_Backend.res.mjs +2 -4
  69. package/src/adapter/Monitoring/Monitoring_CloudWatch.res +16 -16
  70. package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res +5 -10
  71. package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res +4 -2
  72. package/src/adapter/Postgres/PgConnection.res +6 -5
  73. package/src/adapter/Postgres/PgMigration_Builder.res +4 -8
  74. package/src/adapter/Postgres/PgRuntime.res +4 -7
  75. package/src/adapter/QueryDb/PgQueryResolver_Builder.res +9 -11
  76. package/src/adapter/QueryDb/PgQueryResolver_Lambda.res +22 -21
  77. package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +114 -111
  78. package/src/adapter/QueryDb/QueryDbResolvers_Lambda.res +1 -7
  79. package/src/adapter/QueryDb/QueryDbStorage.res +4 -2
  80. package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res +23 -24
  81. package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res +8 -2
  82. package/src/adapter/QueryDb/QueryDbStorage_DynamoDb_Runtime.res +71 -73
  83. package/src/adapter/QueryDb/QueryDbStorage_Postgres.res +5 -2
  84. package/src/adapter/QueryDb/QueryInterceptor_Provisioning.res +1 -4
  85. package/src/adapter/QueryEngine/QueryEngine_DynamoDb.res +8 -2
  86. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +73 -81
  87. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +72 -78
  88. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res +44 -67
  89. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res +44 -67
  90. package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res +53 -82
  91. package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res +47 -77
  92. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +23 -11
  93. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +5 -1
  94. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +80 -97
  95. package/src/adapter/Runtime/CounterEntryPoint_Ops.res +2 -7
  96. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +16 -10
  97. package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +24 -15
  98. package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res +17 -37
  99. package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +31 -57
  100. package/src/adapter/Runtime/EventMapperEntryPoint_Ops.res +18 -24
  101. package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res +1 -5
  102. package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res +4 -3
  103. package/src/adapter/Runtime/HeartbeatEntryPoint.res +0 -1
  104. package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res +4 -2
  105. package/src/adapter/Runtime/PgMigrationEntryPoint.res +0 -1
  106. package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +3 -2
  107. package/src/adapter/Runtime/PluginExtensionPointEntryPoint.res +1 -2
  108. package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res +4 -5
  109. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +22 -10
  110. package/src/adapter/Runtime/RuntimeExtensionEntryPoint_Ops.res +8 -2
  111. package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res +14 -31
  112. package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +16 -17
  113. package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +10 -9
  114. package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res +46 -52
  115. package/src/adapter/Runtime/StreamRoutedEntryPoint_Ops.res +36 -41
  116. package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +31 -37
  117. package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res +6 -7
  118. package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res +4 -6
  119. package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents_Runtime.res +2 -6
  120. package/src/adapter/StateTopic/StateTopic_AppSync.res +21 -16
  121. package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res +36 -32
  122. package/src/adapter/Task/TaskBucket_S3.res +6 -1
  123. package/src/adapter/Upload/Upload_Claim_S3.res +17 -20
  124. package/src/adapter/Upload/Upload_Claim_S3_Ops.res +5 -2
  125. package/src/adapter/Upload/Upload_Presign_S3.res +51 -49
  126. package/src/capability/Capability_Geocoding_AwsLocation.res +4 -1
  127. package/src/capability/Capability_Messaging.res +4 -5
  128. package/src/capability/Capability_Messaging_Ses.res +3 -1
  129. package/src/capability/Capability_ObjectStore_S3.res +1 -7
  130. package/src/components/Api/AppSync_Adapter.res +80 -109
  131. package/src/components/Api/AppSync_Adapter.res.mjs +26 -60
  132. package/src/components/Api/AppSync_SdlDecorate.res +118 -31
  133. package/src/components/Api/AppSync_SdlDecorate.res.mjs +45 -0
  134. package/src/components/AutomationSlice_Builder.res +6 -4
  135. package/src/components/ExtensionPoint_Builder.res +9 -10
  136. package/src/components/InboundTranslationSlice_Builder.res +7 -8
  137. package/src/components/OutboundTranslationSlice_Builder.res +14 -8
  138. package/src/components/OutboundTranslationSlice_Builder.res.mjs +1 -1
  139. package/src/components/SideEffectHandler_Single.res +4 -4
  140. package/src/components/StateViewSlice_Builder.res +6 -4
  141. package/src/components/StateViewSlice_Builder_Stream.res +6 -4
  142. package/src/components/Task_Builder_PerBucket.res +10 -11
  143. package/src/plugin/cloner/ClonerRunner_Fargate.res +3 -10
  144. package/src/plugin/cloner/ClonerRunner_Fargate_Runtime.res +1 -4
  145. package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res +5 -5
  146. package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +19 -21
  147. package/src/plugin/runtime/PluginRuntime_Builder.res +167 -188
  148. package/src/plugin/runtime/Util_PluginMessage_Runtime.res +6 -5
  149. package/src/plugin/stack/Plugin_Stack.res +104 -103
  150. package/src/util/Util_AlarmSpec.res +2 -1
  151. package/src/util/Util_AppSync.res +8 -2
  152. package/src/util/Util_AppSync_Caller.res +15 -14
  153. package/src/util/Util_Bundle.res +46 -42
  154. package/src/util/Util_CognitoGroupUser_Runtime.res +32 -34
  155. package/src/util/Util_Cognito_Runtime.res +11 -7
  156. package/src/util/Util_DeadLetterQueue.res +12 -2
  157. package/src/util/Util_DynamoDb.res +5 -3
  158. package/src/util/Util_DynamoDbStream.res +7 -3
  159. package/src/util/Util_DynamoDbStream_Runtime.res +1 -2
  160. package/src/util/Util_DynamoDb_Runtime.res +23 -41
  161. package/src/util/Util_HostUiDomain.res +6 -1
  162. package/src/util/Util_Kinesis_Runtime.res +10 -11
  163. package/src/util/Util_Lambda.res +12 -5
  164. package/src/util/Util_LambdaEnvBudget.res +5 -5
  165. package/src/util/Util_LambdaLogging.res +1 -2
  166. package/src/util/Util_LogGroup_Adopting.res +1 -4
  167. package/src/util/Util_ResourceNaming.res +1 -2
  168. package/src/util/Util_SNS.res +8 -3
  169. package/src/util/Util_SNS_FIFO.res +1 -1
  170. package/src/util/Util_SNS_Runtime.res +11 -10
  171. package/src/util/Util_SQS.res +4 -2
  172. package/src/util/Util_SQS_FIFO.res +5 -2
  173. package/src/util/Util_SQS_Runtime.res +37 -36
  174. package/src/util/Util_ShellConfig.res +3 -2
  175. package/src/util/Util_StaticBundle.res +1 -3
  176. package/src/util/Util_StoreLayout.res +4 -1
  177. package/tests/AWS_TagsTest.res +16 -5
  178. package/tests/AppSyncEventsSigner_OpsTest.res +11 -2
  179. package/tests/AppSync_AdapterTest.res +286 -224
  180. package/tests/AppSync_AdapterTest.res.mjs +69 -0
  181. package/tests/AppSync_Resolver_RetryingTest.res +64 -44
  182. package/tests/AppSync_RetirementNarrowingTest.res +59 -46
  183. package/tests/AppSync_SdlDecorateTest.res +22 -20
  184. package/tests/AppSync_SourceApiAssociation_RetryingTest.res +40 -22
  185. package/tests/Auth_ActiveRolePoolAttachmentTest.res +114 -107
  186. package/tests/Auth_ActiveRoleStoreTest.res +12 -9
  187. package/tests/Auth_ActiveRoleStore_SchemaTest.res +2 -1
  188. package/tests/Auth_ActiveRoleTrigger_OpsTest.res +20 -16
  189. package/tests/Auth_CognitoTest.res +31 -46
  190. package/tests/Auth_LoginIdentifierTest.res +51 -0
  191. package/tests/Auth_LoginIdentifierTest.res.mjs +51 -0
  192. package/tests/Auth_SignUpModeTest.res +56 -0
  193. package/tests/Auth_SignUpModeTest.res.mjs +53 -0
  194. package/tests/AutomationSliceEntryPoint_OpsTest.res +69 -67
  195. package/tests/BakeConvergenceTest.res +22 -25
  196. package/tests/Capability_MessagingTest.res +28 -12
  197. package/tests/CommandTopicQueuePolicyTest.res +1 -2
  198. package/tests/CounterEntryPoint_OpsTest.res +3 -7
  199. package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +306 -210
  200. package/tests/EventCollectorConnectLambdaPreviewTest.res +14 -7
  201. package/tests/EventCollectorEntryPoint_OpsTest.res +12 -4
  202. package/tests/EventCollectorPluginDefinitionAssetTest.res +18 -11
  203. package/tests/EventCollectorReadyGateTest.res +5 -4
  204. package/tests/EventLogStorage_DynamoDb_RuntimeTest.res +1 -2
  205. package/tests/EventMapperEntryPoint_OpsTest.res +1 -3
  206. package/tests/ExtensionPointEntryPoint_OpsTest.res +1 -4
  207. package/tests/HandlerFactoryDispatchTest.res +97 -70
  208. package/tests/MCP_LambdaTest.res +16 -27
  209. package/tests/PgChangeFeedRelay_IntegrationTest.res +123 -93
  210. package/tests/PgChangeFeedRelay_RuntimeTest.res +13 -10
  211. package/tests/PgMigrationEntryPoint_IntegrationTest.res +0 -1
  212. package/tests/PgPipeline_IntegrationTest.res +80 -66
  213. package/tests/PgQueryDbUnion_IntegrationTest.res +1 -2
  214. package/tests/PgQueryResolverEntryPoint_OpsTest.res +2 -6
  215. package/tests/PgQueryResolver_LambdaTest.res +41 -24
  216. package/tests/Platform_AdminScan_OpsTest.res +4 -1
  217. package/tests/Platform_ComponentDefinitions_Lambda_OpsTest.res +137 -129
  218. package/tests/ProjectionEntryPoint_DisplayNameTest.res +7 -3
  219. package/tests/ProjectionEntryPoint_UnionStampTest.res +3 -2
  220. package/tests/ProvisionAccountsTest.res +142 -0
  221. package/tests/ProvisionAccountsTest.res.mjs +153 -0
  222. package/tests/ProvisionAdminTest.res +55 -0
  223. package/tests/ProvisionAdminTest.res.mjs +66 -0
  224. package/tests/ProvisionIdentityTest.res +91 -9
  225. package/tests/ProvisionIdentityTest.res.mjs +66 -1
  226. package/tests/QueryDbOwnerIndexTableTest.res +6 -4
  227. package/tests/QueryDbResolvers_AppSyncTest.res +23 -16
  228. package/tests/QueryInterceptor_LambdaTest.res +11 -13
  229. package/tests/ReadModelEntryPoint_OpsTest.res +43 -41
  230. package/tests/RuntimeExtensionEntryPoint_OpsTest.res +4 -3
  231. package/tests/SideEffectEntryPoint_OpsTest.res +23 -18
  232. package/tests/StateChangeDescriptorParityTest.res +28 -26
  233. package/tests/StateTopicKeySchemaTest.res +18 -15
  234. package/tests/StateViewSliceEntryPoint_OpsTest.res +55 -44
  235. package/tests/TaskBucketEntryPoint_OpsTest.res +13 -13
  236. package/tests/Upload_ClaimTest.res +3 -3
  237. package/tests/Util_AwsErrorTest.res +4 -7
  238. package/tests/Util_BundleDependencyClosureTest.res +15 -3
  239. package/tests/Util_BundleEsmLoaderTest.res +3 -3
  240. package/tests/Util_BundleResolveTest.res +4 -6
  241. package/tests/Util_BundleRuntimeExtensionTest.res +17 -18
  242. package/tests/Util_DcbMetricsTest.res +6 -6
  243. package/tests/Util_DynamoDbStreamTest.res +4 -5
  244. package/tests/Util_DynamoDbTest.res +3 -2
  245. package/tests/Util_LambdaEnvBudgetTest.res +22 -18
  246. package/tests/Util_LambdaLoggingTest.res +9 -8
  247. package/tests/Util_LogGroup_AdoptingTest.res +10 -5
  248. package/tests/Util_LogRetentionTest.res +6 -2
  249. package/tests/Util_OwnerScopeEnvTest.res +35 -8
  250. package/tests/Util_OwnerScopeEnvTest.res.mjs +13 -0
  251. package/tests/Util_SQS_RuntimeTest.res +5 -7
  252. package/tests/Util_ShellConfigTest.res +7 -17
  253. package/tests/Util_StaticBundleTest.res +3 -8
  254. package/tests/Util_StoreLayoutTest.res +17 -12
  255. package/tests/integration/AggregateEntryPoint_IntegrationTest.res +1 -4
  256. package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res +15 -15
  257. package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res +296 -232
  258. package/tests/integration/DcbIntegrationHarness.res +8 -8
  259. package/tests/integration/EpCompositeSlice.res +16 -8
  260. package/tests/integration/QueryDbUnion_DynamoDb_IntegrationTest.res +8 -10
  261. package/tests/integration/StateViewSliceEntryPoint_IntegrationTest.res +10 -10
  262. package/tests/integration/SvsTestSlice_Projection.res +1 -3
  263. package/tests/util/Util_AlarmSpecTest.res +62 -49
@@ -28,17 +28,21 @@ describe("AppSync_Adapter.injectAwsAuthAll", () => {
28
28
  testSync("adds the Cognito group directive to all mutation fields", () => {
29
29
  let augmented = AppSync_Adapter.injectAwsAuthAll(baseFragment, ~group="Admin")
30
30
  let parts = decodeFragment(augmented)
31
- parts.mutations->Array.forEach(field => {
32
- expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
33
- })
31
+ parts.mutations->Array.forEach(
32
+ field => {
33
+ expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
34
+ },
35
+ )
34
36
  })
35
37
 
36
38
  testSync("adds the Cognito group directive to all query fields", () => {
37
39
  let augmented = AppSync_Adapter.injectAwsAuthAll(baseFragment, ~group="Admin")
38
40
  let parts = decodeFragment(augmented)
39
- parts.queries->Array.forEach(field => {
40
- expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
41
- })
41
+ parts.queries->Array.forEach(
42
+ field => {
43
+ expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
44
+ },
45
+ )
42
46
  })
43
47
 
44
48
  testSync("preserves type definitions unchanged", () => {
@@ -51,9 +55,11 @@ describe("AppSync_Adapter.injectAwsAuthAll", () => {
51
55
  testSync("uses specified group name", () => {
52
56
  let augmented = AppSync_Adapter.injectAwsAuthAll(baseFragment, ~group="SuperAdmin")
53
57
  let parts = decodeFragment(augmented)
54
- parts.mutations->Array.forEach(field => {
55
- expect(field)->toContain(`cognito_groups: ["SuperAdmin"]`)
56
- })
58
+ parts.mutations->Array.forEach(
59
+ field => {
60
+ expect(field)->toContain(`cognito_groups: ["SuperAdmin"]`)
61
+ },
62
+ )
57
63
  })
58
64
 
59
65
  // Regression: `injectAwsAuthAll` used to re-encode the fragment without the
@@ -68,9 +74,11 @@ describe("AppSync_Adapter.injectAwsAuthAll", () => {
68
74
  let parts = decodeFragment(augmented)
69
75
  expect(parts.subscriptions->Array.length)->toBe(original.subscriptions->Array.length)
70
76
  expect(parts.subscriptions->Array.length)->toBeGreaterThan(0)
71
- parts.subscriptions->Array.forEach(field => {
72
- expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
73
- })
77
+ parts.subscriptions->Array.forEach(
78
+ field => {
79
+ expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
80
+ },
81
+ )
74
82
  })
75
83
 
76
84
  testSync("admin Plugin aggregate subscription fields survive the round-trip", () => {
@@ -100,25 +108,20 @@ describe("AppSync_Adapter.injectAwsAuthAll", () => {
100
108
  describe("AppSync_Adapter.injectAwsAuth", () => {
101
109
  testSync("injects auth only on entries with authorization", () => {
102
110
  // Build a fragment with known entries
103
- let mutationEntries: array<ReventlessInfra.Api.mutationSchemaEntry> =
104
- ReventlessCore.Platform_AdminApi.mutationEntries(~cloner=false)
111
+ let mutationEntries: array<
112
+ ReventlessInfra.Api.mutationSchemaEntry,
113
+ > = ReventlessCore.Platform_AdminApi.mutationEntries(~cloner=false)
105
114
  let queryEntries = ReventlessCore.PluginBaseFragment.queryEntries
106
115
 
107
116
  let baseFragment = ReventlessCore.Platform_AdminApi.baseFragment(~cloner=false)
108
- let augmented = AppSync_Adapter.injectAwsAuth(
109
- baseFragment,
110
- ~mutationEntries,
111
- ~queryEntries,
112
- )
117
+ let augmented = AppSync_Adapter.injectAwsAuth(baseFragment, ~mutationEntries, ~queryEntries)
113
118
  let parts = decodeFragment(augmented)
114
119
 
115
120
  // Query entries have authorization → should carry the directive
116
- let queryWithAuth =
117
- queryEntries->Array.some(entry => entry.authorization->Option.isSome)
121
+ let queryWithAuth = queryEntries->Array.some(entry => entry.authorization->Option.isSome)
118
122
  if queryWithAuth {
119
- let hasAuthQuery = parts.queries->Array.some(field =>
120
- field->String.includes("@aws_cognito_user_pools")
121
- )
123
+ let hasAuthQuery =
124
+ parts.queries->Array.some(field => field->String.includes("@aws_cognito_user_pools"))
122
125
  expect(hasAuthQuery)->toBe(true)
123
126
  }
124
127
  })
@@ -177,59 +180,37 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
177
180
  returnTypeName: single,
178
181
  stateSchema: S.unknown,
179
182
  authorization: None,
180
- permission: ?permission,
183
+ ?permission,
181
184
  }
182
185
 
183
186
  testSync("AllowGroups([\"Admin\"]) emits cognito_groups: [\"Admin\"] on mutation", () => {
184
- let fp = Dict.fromArray([(
185
- "catalog_Category_Archive",
186
- Reventless.Authorization.AllowGroups(["Admin"]),
187
- )])
188
- let entry = mutationEntry(
189
- ~fieldNames=["catalog_Category_Archive"],
190
- ~fieldPermissions=fp,
191
- )
187
+ let fp = Dict.fromArray([
188
+ ("catalog_Category_Archive", Reventless.Authorization.AllowGroups(["Admin"])),
189
+ ])
190
+ let entry = mutationEntry(~fieldNames=["catalog_Category_Archive"], ~fieldPermissions=fp)
192
191
  let frag = makeFragment(["catalog_Category_Archive(id: ID!): String"], [])
193
- let aug = AppSync_Adapter.injectAwsAuth(
194
- frag,
195
- ~mutationEntries=[entry],
196
- ~queryEntries=[],
197
- )
192
+ let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
198
193
  let parts = decodeFragment(aug)
199
194
  let m = parts.mutations->Array.getUnsafe(0)
200
195
  expect(m)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
201
196
  })
202
197
 
203
198
  testSync("AllowGroups multi-group emits comma-separated groups", () => {
204
- let fp = Dict.fromArray([(
205
- "p_X",
206
- Reventless.Authorization.AllowGroups(["Admin", "Editor"]),
207
- )])
199
+ let fp = Dict.fromArray([("p_X", Reventless.Authorization.AllowGroups(["Admin", "Editor"]))])
208
200
  let entry = mutationEntry(~fieldNames=["p_X"], ~fieldPermissions=fp)
209
201
  let frag = makeFragment(["p_X(id: ID!): String"], [])
210
- let aug = AppSync_Adapter.injectAwsAuth(
211
- frag,
212
- ~mutationEntries=[entry],
213
- ~queryEntries=[],
214
- )
202
+ let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
215
203
  let parts = decodeFragment(aug)
216
- expect(parts.mutations->Array.getUnsafe(0))->toContain(
217
- `@aws_cognito_user_pools(cognito_groups: ["Admin", "Editor"])`,
218
- )
204
+ expect(
205
+ parts.mutations->Array.getUnsafe(0),
206
+ )->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin", "Editor"])`)
219
207
  })
220
208
 
221
209
  testSync("AllowAuthenticated emits the group-less Cognito directive", () => {
222
- let fp = Dict.fromArray([(
223
- "p_Add",
224
- Reventless.Authorization.AllowAuthenticated,
225
- )])
210
+ let fp = Dict.fromArray([("p_Add", Reventless.Authorization.AllowAuthenticated)])
226
211
  let entry = mutationEntry(~fieldNames=["p_Add"], ~fieldPermissions=fp)
227
212
  let frag = makeFragment(["p_Add(id: ID!): String"], [])
228
- let aug = AppSync_Adapter.injectAwsAuth(
229
- frag,
230
- ~mutationEntries=[entry],
231
- ~queryEntries=[],
232
- )
213
+ let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
233
214
  let parts = decodeFragment(aug)
234
215
  // Open, not ungated: the field carries the group-less directive so it stays
235
216
  // reachable once defaultAction flips to DENY, but names no group.
@@ -242,11 +223,7 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
242
223
  let fp = Dict.fromArray([("p_Hide", Reventless.Authorization.DenyAll)])
243
224
  let entry = mutationEntry(~fieldNames=["p_Hide"], ~fieldPermissions=fp)
244
225
  let frag = makeFragment(["p_Hide(id: ID!): String"], [])
245
- let aug = AppSync_Adapter.injectAwsAuth(
246
- frag,
247
- ~mutationEntries=[entry],
248
- ~queryEntries=[],
249
- )
226
+ let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
250
227
  let parts = decodeFragment(aug)
251
228
  expect(parts.mutations->Array.getUnsafe(0))->toContain(`"__deny_all__"`)
252
229
  })
@@ -256,19 +233,9 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
256
233
  ("p_Archive", Reventless.Authorization.AllowGroups(["Admin"])),
257
234
  ("p_Add", Reventless.Authorization.AllowAuthenticated),
258
235
  ])
259
- let entry = mutationEntry(
260
- ~fieldNames=["p_Archive", "p_Add"],
261
- ~fieldPermissions=fp,
262
- )
263
- let frag = makeFragment(
264
- ["p_Archive(id: ID!): String", "p_Add(name: String!): String"],
265
- [],
266
- )
267
- let aug = AppSync_Adapter.injectAwsAuth(
268
- frag,
269
- ~mutationEntries=[entry],
270
- ~queryEntries=[],
271
- )
236
+ let entry = mutationEntry(~fieldNames=["p_Archive", "p_Add"], ~fieldPermissions=fp)
237
+ let frag = makeFragment(["p_Archive(id: ID!): String", "p_Add(name: String!): String"], [])
238
+ let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
272
239
  let parts = decodeFragment(aug)
273
240
  let archive = parts.mutations->Array.find(f => f->String.includes("p_Archive"))
274
241
  let add = parts.mutations->Array.find(f => f->String.includes("p_Add"))
@@ -295,16 +262,9 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
295
262
  // paren-first split reliably yields the bare field name.
296
263
  let frag = makeFragment(
297
264
  [],
298
- [
299
- "p_Item(id: ID!): Item",
300
- "p_Items(first: Int, after: String): ItemConnection!",
301
- ],
302
- )
303
- let aug = AppSync_Adapter.injectAwsAuth(
304
- frag,
305
- ~mutationEntries=[],
306
- ~queryEntries=[entry],
265
+ ["p_Item(id: ID!): Item", "p_Items(first: Int, after: String): ItemConnection!"],
307
266
  )
267
+ let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[], ~queryEntries=[entry])
308
268
  let parts = decodeFragment(aug)
309
269
  let item = parts.queries->Array.find(f => f->String.includes("p_Item("))
310
270
  let items = parts.queries->Array.find(f => f->String.includes("p_Items("))
@@ -316,13 +276,93 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
316
276
  }
317
277
  })
318
278
 
279
+ // ── AllowAnonymous is refused, not silently downgraded ────────────────────
280
+ //
281
+ // The defect these cover: `AllowAnonymous` shared `AllowAuthenticated`'s arm
282
+ // and emitted the same group-less directive, which on this Cognito-primary
283
+ // API means *any authenticated caller* — the inverse of the declaration. It
284
+ // deployed green, passed `assertGateable`, and worked on the local platform,
285
+ // whose resolvers call `Authorization.isAllowed` and honour the rule. It
286
+ // failed closed, so no deployment ever reported it.
287
+
288
+ let refuses = (run: unit => 'a): bool =>
289
+ switch run() {
290
+ | _ => false
291
+ | exception _ => true
292
+ }
293
+
294
+ let messageOf = (run: unit => 'a): string =>
295
+ switch run() {
296
+ | _ => ""
297
+ | exception JsExn(err) => JsExn.message(err)->Option.getOr("")
298
+ | exception _ => ""
299
+ }
300
+
301
+ let anonymousMutation = (~fieldNames) => {
302
+ let fp =
303
+ fieldNames
304
+ ->Array.map(n => (n, Reventless.Authorization.AllowAnonymous))
305
+ ->Dict.fromArray
306
+ let entry = mutationEntry(~fieldNames, ~fieldPermissions=fp)
307
+ let frag = makeFragment(fieldNames->Array.map(n => `${n}(id: ID!): String`), [])
308
+ () => AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
309
+ }
310
+
311
+ testSync("AllowAnonymous on a mutation fails the deploy", () => {
312
+ expect(refuses(anonymousMutation(~fieldNames=["p_Register"])))->toBe(true)
313
+ })
314
+
315
+ // The whole point of the change: two distinct permissions must not produce
316
+ // one outcome. Asserting only "it throws" would still pass if a later edit
317
+ // re-collapsed the arms and dropped the refusal, so pin the contrast.
318
+ testSync("AllowAnonymous and AllowAuthenticated do not behave alike", () => {
319
+ let authenticated = {
320
+ let fp = Dict.fromArray([("p_Register", Reventless.Authorization.AllowAuthenticated)])
321
+ let entry = mutationEntry(~fieldNames=["p_Register"], ~fieldPermissions=fp)
322
+ let frag = makeFragment(["p_Register(id: ID!): String"], [])
323
+ () => AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
324
+ }
325
+ expect(refuses(authenticated))->toBe(false)
326
+ expect(refuses(anonymousMutation(~fieldNames=["p_Register"])))->toBe(true)
327
+ })
328
+
329
+ testSync("the refusal names the offending field, so it can be found", () => {
330
+ let msg = messageOf(anonymousMutation(~fieldNames=["p_Register"]))
331
+ expect(msg)->toContain("p_Register")
332
+ expect(msg)->toContain("AllowAnonymous")
333
+ })
334
+
335
+ // One deploy should report every offending field. Reporting the first one
336
+ // turns a batch of them into as many failed deploys as there are fields.
337
+ testSync("every offending field is reported, not just the first", () => {
338
+ let msg = messageOf(anonymousMutation(~fieldNames=["p_Register", "p_Confirm"]))
339
+ expect(msg)->toContain("p_Register")
340
+ expect(msg)->toContain("p_Confirm")
341
+ })
342
+
343
+ testSync("AllowAnonymous on a query names BOTH derived field names", () => {
344
+ let entry = queryEntry(
345
+ ~single="p_Item",
346
+ ~list="p_Items",
347
+ ~permission=Some(Reventless.Authorization.AllowAnonymous),
348
+ )
349
+ let frag = makeFragment(
350
+ [],
351
+ ["p_Item(id: ID!): Item", "p_Items(first: Int, after: String): ItemConnection!"],
352
+ )
353
+ let run = () => AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[], ~queryEntries=[entry])
354
+ expect(refuses(run))->toBe(true)
355
+ let msg = messageOf(run)
356
+ // The spec declares one permission and the generator emits two fields from
357
+ // it; naming one would send the author hunting a declaration that is not there.
358
+ expect(msg)->toContain("p_Item")
359
+ expect(msg)->toContain("p_Items")
360
+ })
361
+
319
362
  testSync("Spec-level permission wins over legacy authorization field", () => {
320
363
  // Legacy {tableName, group} says "Admin"; spec-level says "Manager".
321
364
  // Spec-level must win.
322
- let fp = Dict.fromArray([(
323
- "p_X",
324
- Reventless.Authorization.AllowGroups(["Manager"]),
325
- )])
365
+ let fp = Dict.fromArray([("p_X", Reventless.Authorization.AllowGroups(["Manager"]))])
326
366
  let entry: ReventlessInfra.Api.mutationSchemaEntry = {
327
367
  fieldNames: ["p_X"],
328
368
  commandSchema: S.unknown,
@@ -333,44 +373,36 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
333
373
  fieldPermissions: fp,
334
374
  }
335
375
  let frag = makeFragment(["p_X(id: ID!): String"], [])
336
- let aug = AppSync_Adapter.injectAwsAuth(
337
- frag,
338
- ~mutationEntries=[entry],
339
- ~queryEntries=[],
340
- )
376
+ let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
341
377
  let parts = decodeFragment(aug)
342
378
  let m = parts.mutations->Array.getUnsafe(0)
343
379
  expect(m)->toContain(`cognito_groups: ["Manager"]`)
344
380
  expect(m)->not_->toContain(`"Admin"`)
345
381
  })
346
382
 
347
- testSync("AllowAuthenticated on a field overrides the legacy authorization (drops the group)", () => {
348
- let fp = Dict.fromArray([(
349
- "p_X",
350
- Reventless.Authorization.AllowAuthenticated,
351
- )])
352
- let entry: ReventlessInfra.Api.mutationSchemaEntry = {
353
- fieldNames: ["p_X"],
354
- commandSchema: S.unknown,
355
- authorization: {
356
- Reventless.ReadModel.tableName: "Tbl",
357
- group: "Admin",
358
- },
359
- fieldPermissions: fp,
360
- }
361
- let frag = makeFragment(["p_X(id: ID!): String"], [])
362
- let aug = AppSync_Adapter.injectAwsAuth(
363
- frag,
364
- ~mutationEntries=[entry],
365
- ~queryEntries=[],
366
- )
367
- let parts = decodeFragment(aug)
368
- // The spec-level AllowAuthenticated wins over the legacy `authorization.group`:
369
- // the field keeps a directive, but no longer names a group.
370
- let m = parts.mutations->Array.getUnsafe(0)
371
- expect(m)->toContain("@aws_cognito_user_pools")
372
- expect(m)->not_->toContain("cognito_groups")
373
- })
383
+ testSync(
384
+ "AllowAuthenticated on a field overrides the legacy authorization (drops the group)",
385
+ () => {
386
+ let fp = Dict.fromArray([("p_X", Reventless.Authorization.AllowAuthenticated)])
387
+ let entry: ReventlessInfra.Api.mutationSchemaEntry = {
388
+ fieldNames: ["p_X"],
389
+ commandSchema: S.unknown,
390
+ authorization: {
391
+ Reventless.ReadModel.tableName: "Tbl",
392
+ group: "Admin",
393
+ },
394
+ fieldPermissions: fp,
395
+ }
396
+ let frag = makeFragment(["p_X(id: ID!): String"], [])
397
+ let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
398
+ let parts = decodeFragment(aug)
399
+ // The spec-level AllowAuthenticated wins over the legacy `authorization.group`:
400
+ // the field keeps a directive, but no longer names a group.
401
+ let m = parts.mutations->Array.getUnsafe(0)
402
+ expect(m)->toContain("@aws_cognito_user_pools")
403
+ expect(m)->not_->toContain("cognito_groups")
404
+ },
405
+ )
374
406
  })
375
407
 
376
408
  // ── Dual-auth (Cognito + IAM) for deploy-time system callers ────────────────
@@ -394,7 +426,9 @@ describe("AppSync_Adapter.injectAwsAuth — systemCallable dual-auth", () => {
394
426
  let entry: ReventlessInfra.Api.mutationSchemaEntry = {
395
427
  fieldNames: ["p_Sync"],
396
428
  commandSchema: S.unknown,
397
- fieldPermissions: Dict.fromArray([("p_Sync", Reventless.Authorization.AllowGroups(["Admin"]))]),
429
+ fieldPermissions: Dict.fromArray([
430
+ ("p_Sync", Reventless.Authorization.AllowGroups(["Admin"])),
431
+ ]),
398
432
  systemCallable: true,
399
433
  }
400
434
  let frag = makeFragment(["p_Sync(id: ID!): String"], [])
@@ -406,21 +440,24 @@ describe("AppSync_Adapter.injectAwsAuth — systemCallable dual-auth", () => {
406
440
  expect(m)->not_->toContain("@aws_auth")
407
441
  })
408
442
 
409
- testSync("systemCallable mutation without a group restriction stays open to Cognito + IAM", () => {
410
- let entry: ReventlessInfra.Api.mutationSchemaEntry = {
411
- fieldNames: ["p_Sync"],
412
- commandSchema: S.unknown,
413
- fieldPermissions: Dict.fromArray([("p_Sync", Reventless.Authorization.AllowAuthenticated)]),
414
- systemCallable: true,
415
- }
416
- let frag = makeFragment(["p_Sync(id: ID!): String"], [])
417
- let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
418
- let m = decodeFragment(aug).mutations->Array.getUnsafe(0)
419
- // Bare @aws_cognito_user_pools (any authenticated Cognito user) + IAM.
420
- expect(m)->toContain("@aws_cognito_user_pools @aws_iam")
421
- expect(m)->not_->toContain("cognito_groups")
422
- expect(m)->not_->toContain("@aws_auth")
423
- })
443
+ testSync(
444
+ "systemCallable mutation without a group restriction stays open to Cognito + IAM",
445
+ () => {
446
+ let entry: ReventlessInfra.Api.mutationSchemaEntry = {
447
+ fieldNames: ["p_Sync"],
448
+ commandSchema: S.unknown,
449
+ fieldPermissions: Dict.fromArray([("p_Sync", Reventless.Authorization.AllowAuthenticated)]),
450
+ systemCallable: true,
451
+ }
452
+ let frag = makeFragment(["p_Sync(id: ID!): String"], [])
453
+ let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
454
+ let m = decodeFragment(aug).mutations->Array.getUnsafe(0)
455
+ // Bare @aws_cognito_user_pools (any authenticated Cognito user) + IAM.
456
+ expect(m)->toContain("@aws_cognito_user_pools @aws_iam")
457
+ expect(m)->not_->toContain("cognito_groups")
458
+ expect(m)->not_->toContain("@aws_auth")
459
+ },
460
+ )
424
461
 
425
462
  testSync("a non-systemCallable sibling stays Cognito-only (no @aws_iam)", () => {
426
463
  let entry: ReventlessInfra.Api.mutationSchemaEntry = {
@@ -437,11 +474,17 @@ describe("AppSync_Adapter.injectAwsAuth — systemCallable dual-auth", () => {
437
474
  let iamEntry: ReventlessInfra.Api.mutationSchemaEntry = {
438
475
  fieldNames: ["p_Sync"],
439
476
  commandSchema: S.unknown,
440
- fieldPermissions: Dict.fromArray([("p_Sync", Reventless.Authorization.AllowGroups(["Admin"]))]),
477
+ fieldPermissions: Dict.fromArray([
478
+ ("p_Sync", Reventless.Authorization.AllowGroups(["Admin"])),
479
+ ]),
441
480
  systemCallable: true,
442
481
  }
443
482
  let frag = makeFragment(["p_Sync(id: ID!): String", "p_Other(id: ID!): String"], [])
444
- let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry, iamEntry], ~queryEntries=[])
483
+ let aug = AppSync_Adapter.injectAwsAuth(
484
+ frag,
485
+ ~mutationEntries=[entry, iamEntry],
486
+ ~queryEntries=[],
487
+ )
445
488
  let parts = decodeFragment(aug)
446
489
  switch parts.mutations->Array.find(f => f->String.includes("p_Other")) {
447
490
  | Some(other) =>
@@ -480,35 +523,39 @@ describe("AppSync_Adapter.injectAwsAuth — systemCallable dual-auth", () => {
480
523
  }
481
524
  })
482
525
 
483
- testSync("systemCallable dual-auth extends to derived query fields (Items/ByIds/By<Index>)", () => {
484
- let entry: ReventlessInfra.Api.querySchemaEntry = {
485
- singleFieldName: "p_Item",
486
- listFieldName: "p_Items",
487
- returnTypeName: "p_Item",
488
- stateSchema: S.unknown,
489
- authorization: None,
490
- permission: Reventless.Authorization.AllowGroups(["Admin"]),
491
- systemCallable: true,
492
- }
493
- let frag = makeFragment(
494
- [],
495
- [
496
- "p_ItemItems(id: ID!, first: Int): p_ItemConnection!",
497
- "p_ItemsByIds(ids: [ID!]!): [p_Item]!",
498
- "p_ItemByOwner(id: ID!, first: Int): p_ItemConnection!",
499
- "q_Unrelated(id: ID!): String",
500
- ],
501
- )
502
- let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[], ~queryEntries=[entry])
503
- let parts = decodeFragment(aug)
504
- parts.queries->Array.forEach(field =>
505
- if field->String.includes("q_Unrelated") {
506
- expect(field)->not_->toContain("@aws_iam")
507
- } else {
508
- expect(field)->toContain("@aws_iam")
526
+ testSync(
527
+ "systemCallable dual-auth extends to derived query fields (Items/ByIds/By<Index>)",
528
+ () => {
529
+ let entry: ReventlessInfra.Api.querySchemaEntry = {
530
+ singleFieldName: "p_Item",
531
+ listFieldName: "p_Items",
532
+ returnTypeName: "p_Item",
533
+ stateSchema: S.unknown,
534
+ authorization: None,
535
+ permission: Reventless.Authorization.AllowGroups(["Admin"]),
536
+ systemCallable: true,
509
537
  }
510
- )
511
- })
538
+ let frag = makeFragment(
539
+ [],
540
+ [
541
+ "p_ItemItems(id: ID!, first: Int): p_ItemConnection!",
542
+ "p_ItemsByIds(ids: [ID!]!): [p_Item]!",
543
+ "p_ItemByOwner(id: ID!, first: Int): p_ItemConnection!",
544
+ "q_Unrelated(id: ID!): String",
545
+ ],
546
+ )
547
+ let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[], ~queryEntries=[entry])
548
+ let parts = decodeFragment(aug)
549
+ parts.queries->Array.forEach(
550
+ field =>
551
+ if field->String.includes("q_Unrelated") {
552
+ expect(field)->not_->toContain("@aws_iam")
553
+ } else {
554
+ expect(field)->toContain("@aws_iam")
555
+ },
556
+ )
557
+ },
558
+ )
512
559
  })
513
560
 
514
561
  // ── Type-level dual-auth ─────────────────────────────────────────────────────
@@ -551,15 +598,20 @@ describe("AppSync_Adapter — type-level dual-auth", () => {
551
598
 
552
599
  testSync("types prefixed by a callable entry's returnTypeName carry the multi-auth pair", () => {
553
600
  let frag = makeFragmentWithTypes(types, ["p_Item(id: ID!): p_Item"])
554
- let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[], ~queryEntries=[callableEntry])
601
+ let aug = AppSync_Adapter.injectAwsAuth(
602
+ frag,
603
+ ~mutationEntries=[],
604
+ ~queryEntries=[callableEntry],
605
+ )
555
606
  let parts = decodeFragment(aug)
556
- parts.types->Array.forEach(decl =>
557
- if decl->String.startsWith("type p_Item") {
558
- expect(decl)->toContain("@aws_cognito_user_pools @aws_iam {")
559
- } else {
560
- // The sibling view's type and the (non-authorizable) input stay untouched.
561
- expect(decl)->not_->toContain("@aws_iam")
562
- }
607
+ parts.types->Array.forEach(
608
+ decl =>
609
+ if decl->String.startsWith("type p_Item") {
610
+ expect(decl)->toContain("@aws_cognito_user_pools @aws_iam {")
611
+ } else {
612
+ // The sibling view's type and the (non-authorizable) input stay untouched.
613
+ expect(decl)->not_->toContain("@aws_iam")
614
+ },
563
615
  )
564
616
  })
565
617
 
@@ -573,25 +625,31 @@ describe("AppSync_Adapter — type-level dual-auth", () => {
573
625
  decodeFragment(aug).types->Array.forEach(decl => expect(decl)->not_->toContain("@aws_iam"))
574
626
  })
575
627
 
576
- testSync("stampSharedIamTypes marks PageInfo + CommandResult members on the assembled SDL", () => {
577
- let sdl = [
578
- "interface Node {\n id: ID!\n}",
579
- "type PageInfo {\n hasNextPage: Boolean!\n}",
580
- "union CommandResult = CommandAccepted | CommandRejected | CommandPending",
581
- "type CommandAccepted {\n msgId: ID!\n}",
582
- "type CommandRejected {\n msgId: ID!\n}",
583
- "type CommandPending {\n msgId: ID!\n}",
584
- "type Untouched {\n id: ID!\n}",
585
- ]->Array.join("\n\n")
586
- let stamped = AppSync_Adapter.stampSharedIamTypes(sdl)
587
- expect(stamped)->toContain("type PageInfo @aws_cognito_user_pools @aws_iam {")
588
- expect(stamped)->toContain("type CommandAccepted @aws_cognito_user_pools @aws_iam {")
589
- expect(stamped)->toContain("type CommandRejected @aws_cognito_user_pools @aws_iam {")
590
- expect(stamped)->toContain("type CommandPending @aws_cognito_user_pools @aws_iam {")
591
- expect(stamped)->toContain("type Untouched {")
592
- // The union declaration itself takes no directive.
593
- expect(stamped)->toContain("union CommandResult = CommandAccepted | CommandRejected | CommandPending")
594
- })
628
+ testSync(
629
+ "stampSharedIamTypes marks PageInfo + CommandResult members on the assembled SDL",
630
+ () => {
631
+ let sdl =
632
+ [
633
+ "interface Node {\n id: ID!\n}",
634
+ "type PageInfo {\n hasNextPage: Boolean!\n}",
635
+ "union CommandResult = CommandAccepted | CommandRejected | CommandPending",
636
+ "type CommandAccepted {\n msgId: ID!\n}",
637
+ "type CommandRejected {\n msgId: ID!\n}",
638
+ "type CommandPending {\n msgId: ID!\n}",
639
+ "type Untouched {\n id: ID!\n}",
640
+ ]->Array.join("\n\n")
641
+ let stamped = AppSync_Adapter.stampSharedIamTypes(sdl)
642
+ expect(stamped)->toContain("type PageInfo @aws_cognito_user_pools @aws_iam {")
643
+ expect(stamped)->toContain("type CommandAccepted @aws_cognito_user_pools @aws_iam {")
644
+ expect(stamped)->toContain("type CommandRejected @aws_cognito_user_pools @aws_iam {")
645
+ expect(stamped)->toContain("type CommandPending @aws_cognito_user_pools @aws_iam {")
646
+ expect(stamped)->toContain("type Untouched {")
647
+ // The union declaration itself takes no directive.
648
+ expect(stamped)->toContain(
649
+ "union CommandResult = CommandAccepted | CommandRejected | CommandPending",
650
+ )
651
+ },
652
+ )
595
653
  })
596
654
 
597
655
  describe("AppSync_Adapter.injectAwsAuthAll — ~iamFieldNames", () => {
@@ -603,20 +661,25 @@ describe("AppSync_Adapter.injectAwsAuthAll — ~iamFieldNames", () => {
603
661
  decodeFragment(baseFragment).mutations
604
662
  ->Array.getUnsafe(0)
605
663
  ->ReventlessCore.GraphQL_Stitcher.extractLeadingName
606
- let augmented =
607
- AppSync_Adapter.injectAwsAuthAll(baseFragment, ~group="Admin", ~iamFieldNames=[firstMutationName])
664
+ let augmented = AppSync_Adapter.injectAwsAuthAll(
665
+ baseFragment,
666
+ ~group="Admin",
667
+ ~iamFieldNames=[firstMutationName],
668
+ )
608
669
  let parts = decodeFragment(augmented)
609
- parts.mutations->Array.forEach(field => {
610
- let name = ReventlessCore.GraphQL_Stitcher.extractLeadingName(field)
611
- if name == firstMutationName {
612
- expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
613
- expect(field)->toContain("@aws_iam")
614
- expect(field)->not_->toContain("@aws_auth")
615
- } else {
616
- expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
617
- expect(field)->not_->toContain("@aws_iam")
618
- }
619
- })
670
+ parts.mutations->Array.forEach(
671
+ field => {
672
+ let name = ReventlessCore.GraphQL_Stitcher.extractLeadingName(field)
673
+ if name == firstMutationName {
674
+ expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
675
+ expect(field)->toContain("@aws_iam")
676
+ expect(field)->not_->toContain("@aws_auth")
677
+ } else {
678
+ expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
679
+ expect(field)->not_->toContain("@aws_iam")
680
+ }
681
+ },
682
+ )
620
683
  })
621
684
 
622
685
  testSync("default (no ~iamFieldNames) leaves every field Cognito-only", () => {
@@ -670,10 +733,7 @@ describe("Split mode — empty base fragment", () => {
670
733
 
671
734
  testSync("stitching admin base without plugins produces only admin fields", () => {
672
735
  let adminBase = ReventlessCore.Platform_AdminApi.baseFragment(~cloner=false)
673
- let sdl = ReventlessCore.GraphQL_Stitcher.stitch(
674
- ~baseFragment=adminBase,
675
- ~pluginFragments=[],
676
- )
736
+ let sdl = ReventlessCore.GraphQL_Stitcher.stitch(~baseFragment=adminBase, ~pluginFragments=[])
677
737
  expect(sdl)->toContain("Platform_Plugin")
678
738
  })
679
739
  })
@@ -688,8 +748,9 @@ describe("Split mode — empty base fragment", () => {
688
748
 
689
749
  describe("Merged mode — canonical source documents", () => {
690
750
  let assembleCanonicalSourceSdl = (~baseFragment) =>
691
- AppSync_Adapter.stitchStandaloneWithAwsDirectives(~fragment=baseFragment)
692
- ->AppSync_SdlDecorate.stampCanonicalTypes
751
+ AppSync_Adapter.stitchStandaloneWithAwsDirectives(
752
+ ~fragment=baseFragment,
753
+ )->AppSync_SdlDecorate.stampCanonicalTypes
693
754
 
694
755
  // Mirrors Platform.res's domainBaseFragment: no component fields, one
695
756
  // Platform_ping so the Query type is non-empty.
@@ -755,9 +816,7 @@ describe("Merged mode — canonical source documents", () => {
755
816
  mutations: ["MyPlugin_Item_Create(name: String!): CommandResult"],
756
817
  queries: ["MyPlugin_Item(id: ID!): MyPlugin_Item"],
757
818
  subscriptions: ["onMyPlugin_Item_Create(id: ID): CommandResult"],
758
- subscriptionSources: [
759
- {field: "onMyPlugin_Item_Create", mutations: ["MyPlugin_Item_Create"]},
760
- ],
819
+ subscriptionSources: [{field: "onMyPlugin_Item_Create", mutations: ["MyPlugin_Item_Create"]}],
761
820
  })
762
821
 
763
822
  testSync("plugin subgraph document is standalone: relay types included, node omitted", () => {
@@ -768,13 +827,16 @@ describe("Merged mode — canonical source documents", () => {
768
827
  expect(sdl)->not_->toContain("node(id: ID!): Node")
769
828
  })
770
829
 
771
- testSync("plugin subgraph document carries @aws_subscribe + shared-type IAM stamps, no @canonical", () => {
772
- let sdl = AppSync_Adapter.stitchStandaloneWithAwsDirectives(~fragment=pluginFragment)
773
- expect(sdl)->toContain(`@aws_subscribe(mutations: ["MyPlugin_Item_Create"])`)
774
- expect(sdl)->toContain("type CommandAccepted @aws_cognito_user_pools @aws_iam {")
775
- // Plugin subgraphs stay unstamped — the admin source's canonical defs win.
776
- expect(sdl)->not_->toContain("@canonical")
777
- })
830
+ testSync(
831
+ "plugin subgraph document carries @aws_subscribe + shared-type IAM stamps, no @canonical",
832
+ () => {
833
+ let sdl = AppSync_Adapter.stitchStandaloneWithAwsDirectives(~fragment=pluginFragment)
834
+ expect(sdl)->toContain(`@aws_subscribe(mutations: ["MyPlugin_Item_Create"])`)
835
+ expect(sdl)->toContain("type CommandAccepted @aws_cognito_user_pools @aws_iam {")
836
+ // Plugin subgraphs stay unstamped — the admin source's canonical defs win.
837
+ expect(sdl)->not_->toContain("@canonical")
838
+ },
839
+ )
778
840
  })
779
841
 
780
842
  // ── waitForMergeSuccess — association merge-status poll ─────────────────────